Aplikacja internetowa z wykorzystaniem
Transkrypt
Aplikacja internetowa z wykorzystaniem
Politechnika Warszawska Wydział Elektroniki i Technik Informacyjnych Instytut Informatyki Rok akademicki 2013/2014 Praca dyplomowa inżynierska Mateusz Dziurdziak Aplikacja internetowa z wykorzystaniem szkieletu Vaadin Opiekun pracy: dr inż. Jakub Janusz Koperwas Ocena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ......................................... Podpis Przewodniczacego ˛ Komisji Egzaminu Dyplomowego Specjalność: Informatyka – Inżynieria oprogramowania i systemy informacyjne Data urodzenia: 10 kwietnia 1991 r. Data rozpoczecia ˛ studiów: 1 października 2010 r. Życiorys Nazywam sie˛ Mateusz Dziurdziak, urodziłem sie˛ 10 kwietnia 1991 roku w Łukowie. W 2010 roku ukończyłem I Liceum Ogólnokształcace ˛ im. Tadeusza Kościuszki w Łukowie i rozpoczałem ˛ studia na wydziale Elektroniki i Technik Informacyjnych Politechniki Warszawskiej na kierunku Informatyka. W czerwcu 2012 roku podja˛ łem staż w firmie Quality Business Software. We wrześniu 2013 roku rozpoczałem ˛ prac˛e w firmie Accenture. Obecnie kontynuuje˛ studia oraz pracuje˛ w e-point SA na stanowisku młodszego programisty Java. ..................................... podpis studenta Egzamin dyplomowy Złożył egzamin dyplomowy w dn. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Z wynikiem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ogólny wynik studiów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dodatkowe wnioski i uwagi Komisji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .......................................................................................... Streszczenie Praca ta prezentuje procesu projektowania oraz implementacji aplikacji internetowej, która wykorzystuje szkielet Vaadin. Jako temat aplikacji wybrano system wspierajacy ˛ rozliczanie wspólnych wydatków. Poczatek ˛ poświecony ˛ jest analizie wymagań oraz zaznajomieniu czytelnika z dziedzina˛ problemu. W dalszej cze˛ ści dokonano analizy dostepnych ˛ bibliotek oraz szkieletów informatycznych, które mogły zostać wykorzystane podczas tworzenia aplikacji. W ramach projektowania sformułowano model logiczny i fizyczny danych. W pracy zawarto również omówienie sporzadzonego ˛ interfejsu graficznego oraz sposóbu integracji Vaadin ze przygotowanymi modułami bezpieczeństwa oraz nawigacji. Słowa kluczowe: aplikacja internetowa, Vaadin, Apache Shiro, OAuth, wspólne wydatki, wstrzykiwanie zależności. Abstract Title: Web application using Vaadin framework This thesis describes process of design and implementation of web application using Vaadin framework. System supporting accounting of shared expenses has been chosen as the application subject. First part of the thesis is dedicated to describe application requirements and to familiarize reader with problem domain. Next part is about analysis of available libraries and frameworks, which could be used in process of creating application. During design process author created logical and physical data model. This thesis also contains description of grafic user interface and method of integration Vaadin framework with newly implemented security and navigation modules. Key words: web application, Vaadin, Apache Shiro, OAuth, shared expenses, dependency injection. Spis treści 1. Wstep ˛ . . . . . . . . . . 1.1. Motywacja . . . . 1.2. Cel i zakres pracy 1.3. Zawartość pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 2 2. Specyfikacja wymagań . . . . 2.1. Dziedzinowy słownik pojeć ˛ 2.1.1. Użytkownik . . . . . 2.1.2. Znajomy . . . . . . 2.1.3. Grupa . . . . . . . . 2.1.4. Konto . . . . . . . . 2.1.5. Operacja . . . . . . 2.2. Wymagania funkcjonalne 2.3. Reguły biznesowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 3 3 3 4 6 3. Analiza technologiczna . . . . . . . . . . . . . . . . . . . 3.1. Baza danych . . . . . . . . . . . . . . . . . . . . . . . 3.1.1. Oracle Database Express Edition . . . . . . . 3.1.2. SQL Server Express . . . . . . . . . . . . . . . 3.1.3. PostgreSQL . . . . . . . . . . . . . . . . . . . . 3.1.4. Wybrana baza danych . . . . . . . . . . . . . 3.2. Warstwa prezentacji . . . . . . . . . . . . . . . . . . . 3.2.1. AngularJS . . . . . . . . . . . . . . . . . . . . 3.2.2. Vaadin . . . . . . . . . . . . . . . . . . . . . . 3.2.3. Wybrany szkielet warstwy prezentacji . . . . 3.3. Mapowanie obiektowo-relacyjne . . . . . . . . . . . . 3.3.1. Java Persistence API . . . . . . . . . . . . . . 3.3.2. Hibernate . . . . . . . . . . . . . . . . . . . . . 3.3.3. EclipseLink . . . . . . . . . . . . . . . . . . . . 3.3.4. Wybrane rozwiazanie ˛ . . . . . . . . . . . . . . 3.4. Wstrzykiwanie zależności . . . . . . . . . . . . . . . . 3.4.1. Spring . . . . . . . . . . . . . . . . . . . . . . . 3.4.2. Context Dependency Injection . . . . . . . . . 3.4.3. Wybrany kontener wstrzykiwania zależności 3.5. Serwer aplikacyjny . . . . . . . . . . . . . . . . . . . 3.5.1. GlassFish . . . . . . . . . . . . . . . . . . . . . 3.5.2. WildFly . . . . . . . . . . . . . . . . . . . . . . 3.5.3. Wybrany serwer aplikacyjny . . . . . . . . . . 3.6. Moduł bezpieczeństwa . . . . . . . . . . . . . . . . . 3.6.1. Spring Security . . . . . . . . . . . . . . . . . 3.6.2. Apache Shiro . . . . . . . . . . . . . . . . . . . 3.6.3. OAuth . . . . . . . . . . . . . . . . . . . . . . . 3.6.4. Wybrany szkielet bezpieczeństwa . . . . . . . 3.7. Testowanie jednostkowe . . . . . . . . . . . . . . . . 3.7.1. JUnit . . . . . . . . . . . . . . . . . . . . . . . 3.7.2. TestNG . . . . . . . . . . . . . . . . . . . . . . 3.7.3. Wybrany szkielet testujacy ˛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 9 9 9 10 10 11 12 13 13 14 14 15 15 16 17 18 19 19 19 20 20 20 21 22 23 24 24 25 26 ii Spis treści 3.8. Makietowanie . . . . . . . . . . . . . . . 3.8.1. Mockito . . . . . . . . . . . . . . . 3.8.2. EasyMock . . . . . . . . . . . . . 3.8.3. Wybrana biblioteka makietujaca ˛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 26 27 28 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 29 30 31 34 34 38 39 39 39 41 5. Interfejs graficzny . . . . . . . . . . . . . . . . . . 5.1. Okno dodawania operacji grupowej . . . . . . 5.2. Okno dodawania operacji w parze . . . . . . . 5.3. Ekran szczegółów grupy . . . . . . . . . . . . 5.4. Ekran szczegółów konta z użytkownikiem . . 5.5. Ekran operacji pomiedzy ˛ użytkownikami . . 5.6. Ekran kont pomiedzy ˛ użytkownikami . . . . 5.7. Ekran wyświetlajacy ˛ informacje o znajomym 5.8. Formularz uwierzytelniania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 42 43 43 44 44 45 46 46 6. Implementacja rozszerzeń szkieletu Vaadin . . . 6.1. Moduł bezpieczeństwa . . . . . . . . . . . . . . 6.1.1. Rozwiazanie ˛ dostepne ˛ w Apache Shiro . 6.1.2. Wymagania wobec nowego rozwiazania ˛ 6.1.3. Integracja z baza˛ danych . . . . . . . . . 6.1.4. Rodzaje uprawnień . . . . . . . . . . . . 6.1.5. Sprawdzanie uprawnień . . . . . . . . . 6.2. MVP oraz nawigacja . . . . . . . . . . . . . . . . 6.2.1. Sposób nawigacji w Vaadin . . . . . . . 6.2.2. Wady nawigacji w Vaadin . . . . . . . . . 6.2.3. Wymagania wobec nowego rozwiazania ˛ 6.2.4. Wykorzystane rozwiazanie ˛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 47 47 47 48 51 52 53 53 53 54 54 7. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 4. Projekt systemu . . . . . . . . . . 4.1. Architektura . . . . . . . . . . 4.2. Podział pakietów . . . . . . . . 4.3. Testowanie . . . . . . . . . . . 4.4. Wyjatki ˛ . . . . . . . . . . . . . 4.5. Model logiczny . . . . . . . . . 4.6. Model klas operacji . . . . . . 4.7. Model klas kont . . . . . . . . 4.8. Model fizyczny . . . . . . . . . 4.8.1. Operacje oraz konta . . 4.8.2. Moduł bezpieczeństwa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1. Wstep ˛ 1.1. Motywacja W środowisku studenckim powszechne jest dokonywanie wspólnych zakupów lub wydatków, które naste˛ pnie należy podzielić pomiedzy ˛ grono osób. Zwiazane ˛ jest to z cze˛ stym w tym wieku współdzieleniem mieszkań oraz grupowym sp˛edzaniem wolnego czasu. W przypadku dokonywania dużej liczby wydatków do rangi problemu urasta sposób dokonania rozliczenia. W sieci Internet doste˛ pne sa˛ aplikacje majace ˛ usprawnić czynności zwiazane ˛ ze wspólnym rozliczaniem np.: — www.splitwise.com — www.expensesplit.com — www.kittysplit.com Przedstawione powyżej strony internetowe maja˛ jednak mankamenty m.in.: — Możliwość rozliczania tylko pojedynczego wyjazdu, wydarzenia. — Ograniczona liczba osób bioracych ˛ udział w operacji. — Możliwość przynależenia do tylko jednej grupy. — Brak sposobności dodawania wydatków o nierównym podziale udziałów pomie˛ dzy uczestników. — Brak polskiej wersji je˛ zykowej. Nie każda z wymienionych wad dotyczy wszystkich serwisów, lecz żaden z nich nie spełnia wszystkich stawianych przed nim wymagań. W zwiazku ˛ z tym autor tej pracy podjał ˛ decyzje˛ o zaimplementowaniu aplikacji majacej ˛ niwelować trudności wspólnego rozliczania, która w miare˛ możliwości pozbawiona bedzie ˛ niedostatków przedstawionych powyżej stron internetowych. 1.2. Cel i zakres pracy Celem pracy jest implementacja bogatej aplikacji internetowej (ang. Rich Internet Application) wspomagajacej ˛ rozliczanie wspólnych wydatków. Dodatkowym elementem jest przeglad ˛ i poznanie dostepnych ˛ technik oraz technologii informatycznych. Zadaniem, które należało wkomponować w proces pisania kodu źródłowego była integracja technologii wybranych do tworzenia systemu. Skupiła sie˛ ona na stworzeniu komponentu odpowiedzialnego za połaczenie ˛ modułu bezpieczeństwa (Apache Shiro) z Vaadin oraz na opracowaniu własnego sposobu nawigacji. Oba zaproponowane rozwiazania ˛ podczas swojego działania wykorzystuja˛ wstrzykiwanie zależności. Projektowana aplikacja ma za zadanie umożliwiać zarejestrowanym użytkownikom na przynależenie do grup, posiadanie znajomych w jej obrebie, ˛ dodawanie 1.3. Zawartość pracy 2 wydatków wspólnych oraz pomiedzy ˛ dwoma użytkownikami. Bilans operacji z innymi użytkownikami powinien być gromadzony na specjalnych kontach. Dodatkowa˛ funkcja˛ systemu powinno być ułatwienie uwierzytelniania poprzez możliwość wykorzystania standardu OAuth. 1.3. Zawartość pracy — Rozdział 2 (”Specyfikacja wymagań”) zawiera krótki spis pojeć ˛ zwiazanych ˛ z tematyka˛ aplikacji oraz omawia wymagania jakie bedzie ˛ musiał spełnić projektowany system. — Rozdział 3 (”Analiza technologiczna”) jest zapisem przeprowadzonej w trakcie pracy analizy doste˛ pnych technologii. Przedstawia biblioteki oraz szkielety aplikacyjne wraz z ich alternatywami, które mogły zostać wykorzystane w trakcie implementacji systemu. — Rozdział 4 (”Projekt systemu”) prezentuje sposób organizacji danych, które zostały wykorzystane w aplikacji oraz omawia decyzje, które wpłyneły ˛ na proces tworzenia aplikacji. — Rozdział 5 (”Interfejs graficzny”) prezentuje najważniejsze elementy interfejsu graficznego aplikacji. — Rozdział 6 (”Implementacja rozszerzeń szkieletu Vaadin”) zawiera opis pracy wykonanej w celu integracji szkieletu Vaadin z zewnetrznymi ˛ bibliotekami. W pierwszej cze˛ ści omówiony jest proces integracji z Apache Shiro. W drugiej przedstawiono powody, dla których podjeto ˛ decyzje˛ o implementacji własnego modułu nawigacyjnego oraz sposób jego wykonania oraz wykorzystania. — Rozdział 7 (”Podsumowanie”) podsumowuje efekty pracy oraz przedstawia możliwe dalsze kierunki rozwoju. 2. Specyfikacja wymagań 2.1. Dziedzinowy słownik pojeć ˛ 2.1.1. Użytkownik Użytkownik jest osoba˛ korzystajac ˛ a˛ z aplikacji. Istnieja˛ dwa stany, w których może przebywać użytkownik: — nieuwierzytelniony, — uwierzytelniony. Użytkownik nieuwierzytelniony nie ma możliwości wykonania żadnej operacji z wyjatkiem ˛ procedury rejestracji lub uwierzytelnienia. Uwierzytelniony użytkownik ma możliwość tworzenia kont, operacji finansowych, grup, wysyłania zaproszeń do grona znajomych oraz grup, modyfikacji swoich danych. 2.1.2. Znajomy Znajomy jest użytkownikiem, który zaakceptował badź ˛ wysłał zaproszenie do grona znajomych, które zostało zaakceptowane. Gdy dwaj użytkownicy sa˛ znajomymi maja˛ możliwość dodawania operacji finansowych pomiedzy ˛ soba. ˛ 2.1.3. Grupa Grupa jest zbiorem użytkowników, którego członkowie maja˛ na celu wspólne rozliczanie. Jest tworzona i zarzadzana ˛ prze użytkowników. Istnienie grupy umożliwia powiazanie ˛ z nia˛ operacji wspólnych obejmujacych ˛ wszystkich członków. 2.1.4. Konto Konto jest obiektem służacym ˛ do grupowania operacji finansowych. Każde jest przypisane do użytkownika, który jest jego właścicielem. Istnieja˛ naste˛ pujace ˛ rodzaje kont: — wirtualne – określane też własnymi, służa˛ do grupowania operacji wirtualnych, — użytkownika – służace ˛ do notowania operacji pomiedzy ˛ użytkownikami 2.1.5. Operacja Operacja˛ nazywa sie˛ pojedynczy fakt dokumentujacy ˛ wydatek poniesiony przez użytkownika lub użytkowników. Istnieja˛ naste˛ pujace ˛ rodzaje operacji: — Wirtualna – operacja własna użytkownika. Służy np. do notowania bieżacych ˛ wydatków. 2.2. Wymagania funkcjonalne 4 — Pożyczka – operacja pomie˛ dzy dwoma użytkownikami, której wynikiem jest przekazanie pienie˛ dzy pomie˛ dzy nimi. Całość kwoty operacji zapisywana jest na kontach użytkowników. — W parze – wspólny wydatek dwóch użytkowników. Kwota operacji dzielona jest pomie˛ dzy jej uczestników. — Wspólna – operacja dotyczaca ˛ wiecej ˛ niż dwóch użytkowników. Całkowita kwota operacji dzielona jest pomiedzy ˛ użytkowników. — Grupowa – jest to operacja wspólna, której uczestnikami sa˛ członkowie jednej grupy. 2.2. Wymagania funkcjonalne WF 1. Nieuwierzytelniony użytkownik może zarejestrować nowe konto do pracy z aplikacja˛ podajac ˛ nastepuj ˛ ace ˛ dane: — login, — hasło, — adres e-mail. WF 2. Nieuwierzytelniony użytkownik może zarejestrować nowe konto korzystajac ˛ z serwisów trzecich takich jak: — Facebook, — LinkedIn. WF 3. Po zarejestrowaniu użytkownika system wysyła wiadomość e-mail potwierdzajac ˛ a˛ te˛ operacje˛ . WF 4. Nieuwierzytelniony użytkownik ma możliwość uwierzytelnienia sie˛ podajac ˛ login i hasło. WF 5. Nieuwierzytelniony użytkownik ma możliwość uwierzytelnienia sie˛ z wykorzystaniem serwisów trzecich, o ile jego konto zostało wcześniej połaczone ˛ z kontami tamtych serwisów. WF 6. Administrator systemu może zresetować hasło użytkownika. System w takiej sytuacji wyśle nowe hasło na adres poczty elektronicznej powiazanej ˛ z kontem użytkownika. WF 7. Użytkownik ma możliwość zmiany swojego hasła o ile w trakcie tej czynności poprawnie poda aktualne. WF 8. Użytkownik może zaprosić innego użytkownika do listy swoich znajomych podajac ˛ jego login. WF 9. Zaproszony użytkownik ma prawo zaakceptować badź ˛ zignorować zaproszenie do grona znajomych. WF 10. Użytkownik ma możliwość podgladu ˛ listy swoich znajomych. 2.2. Wymagania funkcjonalne 5 WF 11. Użytkownik ma możliwość utworzenia grupy. Podczas tego procesu musi podać jej nazwe˛ . WF 12. Użytkownik ma możliwość podgladu ˛ listy grup, których jest członkiem. WF 13. Użytkownik może zaprosić innego użytkownika do członkostwa w grupie, której sam jest członkiem. WF 14. Członkowie grupy maja˛ możliwość podgladu ˛ listy wysłanych zaproszeń. WF 15. Użytkownik ma możliwość utworzenia konta wirtualnego podajac ˛ jego nazwe˛ . WF 16. Użytkownik może utworzyć konto do rozliczeń z użytkownikiem wybierajac ˛ znajomego, którego konto to ma dotyczyć oraz nazwe˛ konta. WF 17. ˛ list posiadanych kont wirtualnych oraz Użytkownik ma możliwość podgladu kont służacych ˛ do rozliczeń z innymi użytkownikami. WF 18. Użytkownik może zobaczyć liste˛ operacji własnych. WF 19. Użytkownik może zobaczyć liste˛ operacji z innymi użytkownikami. WF 20. Użytkownik może zobaczyć liste˛ operacji grupowych. WF 21. W widoku szczegółowym kont zobrazowany jest bilans dzienny operacji z ostatnich trzydziestu dni. WF 22. Użytkownik może wyświetlić wykresy obrazujace ˛ podsumowanie bilansu wszystkich kont do rozliczeń z użytkownikami. Dostepne ˛ wykresy to: — dłużnicy wg kont rozliczeniowych, — długi użytkownika wzgledem ˛ innych podzielone na konta. WF 23. Użytkownik ma możliwość dodania operacji wirtualnej podajac ˛ nastepuj ˛ ace ˛ dane: nazwa operacji, kwota, data operacji, konto wirtualne, opis (opcjonalnie). WF 24. Użytkownik ma możliwość dodania pożyczki podajac ˛ nastepuj ˛ ace ˛ dane: nazwa operacji, kwota, data operacji, znajomy, konto do rozliczeń ze znajomym (o ile istnieje wie˛ cej niż jedno), opis (opcjonalnie) oraz kierunek pożyczki (kto pożyczył komu). WF 25. Użytkownik ma możliwość dodania operacji w parze podajac ˛ nastepuj ˛ ace ˛ dane: nazwa operacji, kwota, data operacji, znajomy, konto do rozliczeń ze znajomym (o ile istnieje wiecej ˛ niż jedno), opis (opcjonalnie), informacje˛ o tym jak podzielić kwote˛ oraz dodatkowe informacje o sposobie zapłaty. WF 26. Użytkownik ma możliwość dodania operacji wspólnej podajac ˛ nastepuj ˛ ace ˛ 2.3. Reguły biznesowe 6 dane: nazwa operacji, kwota, data operacji, lista znajomych bioracych ˛ udział w operacji, opis (opcjonalnie). Jeśli operacja wspólna była operacja˛ składkowa˛ możliwe jest również podanie kwoty wniesionej przez każdego użytkownika. System umożliwia podglad ˛ operacji pomiedzy ˛ użytkownikami, które zostana˛ wygenerowane w momencie akceptacji operacji. WF 27. Podczas dodawania operacji grupowej użytkownik musi podać te same dane co w przypadku operacji wspólnej z wyłaczeniem ˛ listy uczestników operacji. Lista ta zostanie automatycznie zbudowana na podstawie członków grupy, której dotyczy operacja. WF 28. Użytkownik ma możliwość podgladu ˛ wszystkich operacji, których jest członkiem. WF 29. Użytkownik ma możliwość przegladu ˛ operacji pomiedzy ˛ nim, a innym użytkownikiem. WF 30. Aplikacja powinna blokować użytkownikowi dostep ˛ do ekranów oraz danych dla niego niedozwolonych. WF 31. Aplikacja powinna poprawnie reagować na skorzystanie z opcji Wstecz przegladarki ˛ internetowej. 2.3. Reguły biznesowe RB 1. Login oraz adres e-mail użytkownika musza˛ być unikalne w obrebie ˛ systemu. RB 2. Hasło użytkownika przetrzymywane jest w postaci wielokrotnie przetworzonej za pomoca˛ algorytmu SHA-256. RB 3. Jeśli użytkownik pie˛ ciokrotnie poda nieprawidłowe hasło podczas uwierzytelniania sie˛ jego konto zostaje zablokowane na 5 minut. RB 4. Użytkownik nie może posiadać wiecej ˛ niż sześciu kont wirtualnych. RB 5. Osoba nieuwierzytelniona powinna być przekierowywana do ekranu uwierzytelniania. RB 6. Użytkownik nie może utworzyć wiecej ˛ niż dwudziestu grup. RB 7. Minimalna długość nazwy operacji to trzy znaki. RB 8. Minimalna długość loginu to trzy znaki. RB 9. Minimalna długość hasła to pieć ˛ znaków. 2.3. Reguły biznesowe 7 RB 10. Użytkownik uwierzytelniony nie może mieć dostepu ˛ do ekranów uwierzytelniania oraz rejestracji. RB 11. W przypadku gdy dodawana jest operacja pomiedzy ˛ użytkownikami, a nie istnieje jeszcze pomie˛ dzy nimi konto rozliczeniowe zostanie ono automatycznie utworzone. 3. Analiza technologiczna Celem tego rozdziału jest przedstawienie technologii, których wykorzystanie było rozważane podczas budowania aplikacji internetowej. Z uwagi na mnogość istniejacych ˛ na rynku narze˛ dzi wybór nie był trywialny. 3.1. Baza danych Skomplikowane aplikacje obsługujace ˛ wielu użytkowników oraz przetwarzajace ˛ duże wolumeny danych wymagaja˛ niezawodnego sposobu przechowywania informacji. Jako rozwiazanie ˛ już w latach sześćdziesiatych ˛ XX wieku zaproponowano oddzielny system, którego dedykowanym zadaniem miało być zarzadzanie ˛ danymi. W 1970 roku zaproponowano relacyjny model danych [13]. W modelu tym dane przetrzymywane sa˛ w relacjach bed ˛ acych ˛ zbiorami krotek. Krotki sa˛ uporzadkowa˛ nymi listami wartości. W powszechnym zastosowaniu odpowiednikami relacji sa˛ dwuwymiarowe tabele składajace ˛ sie˛ z kolumn i wierszy. Wraz z upowszechnieniem modelu relacyjnego powstały relacyjne systemy zarzadzania ˛ bazami danych. Obecnie najpopularniejszym tego typu oprogramowaniem jest Oracle Database [2]. Na rynku dostepnych ˛ jest jednocześnie wiele konkurencyjnych systemów wolnodostepnych. ˛ W ostatnich latach rosnac ˛ a˛ popularnościa˛ ciesza˛ sie˛ bazy danych wykorzystujace ˛ mechanizm NoSQL. Polega on na przechowywaniu danych w formie innej niż relacyjna. Możliwymi rozwiazaniami ˛ sa˛ miedzy ˛ innymi: — przechowywanie par klucz-wartość, — przechowywanie dokumentów, — bazy grafowe, — bazy kolumnowe. Z uwagi na tabelaryczny typ danych zastosowany w projektowanej aplikacji oraz konieczność wsparcia dla transakcyjności zdecydowano sie˛ na wykorzystanie relacyjnej bazy danych. 3.1.1. Oracle Database Express Edition Korzenie systemu Oracle Database siegaj ˛ a˛ lat siedemdziesiatych. ˛ System oferowany jest w różnych wersjach, pośród których znalazła sie˛ Oracle Database Express Edition (Oracle Database XE) bed ˛ aca ˛ jedyna˛ darmowa˛ opcja. ˛ Obecna wersja Oracle XE to 11g. Pozostałe warianty dostepne ˛ sa˛ już w nowszej wersji 12c. Oracle poleca darmowa˛ wersje˛ bazy programistom, niezależnym twórcom oprogramowania, instytucjom edukacyjnym oraz studentom [6]. Swoja˛ opinie˛ popiera zapewnieniami o dużych możliwościach, stabilności, niskim wykorzystaniu zasobów sprze˛ towych oraz intuicyjnym zarzadzaniu. ˛ Dzieki ˛ dużej popularności tego systemu bardzo łatwo jest znaleźć rozwiazania ˛ typowych problemów. Podobnie jak płatne warianty Oracle XE oferuje obsługe˛ szerokiej gamy poleceń SQL i PL/SQL, 3.1. Baza danych 9 wspiera przechowywanie dokumentów XML oraz indeksowanie, przeszukiwanie i składowanie tekstów w wysokowydajny sposób [9]. Duża˛ wada˛ tego rozwiazania ˛ sa˛ ograniczenia nałożone przez producenta. Oracle XE może przechowywać maksymalnie 11GB danych, używać nie wiecej ˛ niż 1GB pami˛eci operacyjnej oraz wykorzystywać tylko jeden watek ˛ procesora. Użytkownicy tej wersji systemu pozbawieni sa˛ oficjalnego wsparcia Oracle Support. 3.1.2. SQL Server Express Firma Microsoft, założona w 1975 roku, jest znana głównie ze swojego flagowego produktu Microsoft Windows. Jest on najpopularniejszym system operacyjnym przeznaczonym na komputery osobiste [8]. W 1989 roku Microsoft po raz pierwszy udoste˛ pnił baze˛ danych o nazwie SQL Server. Obecnie najnowsza˛ wersja˛ jest SQL Server 2014, jest ona dwunastym wydaniem tego systemu. Podobnie jak w przypadku Oracle, Microsoft oferuje swój system w wielu wariantach różniacych ˛ si˛e możliwościami i cena. ˛ SQL Server Express jest darmowa˛ wersja˛ bazy danych o znacznie okrojonych, w stosunku do wariantów płatnych, możliwościach. Pozwala ona na stosowanie j˛ezyka Transact-SQL be˛ dacego ˛ rozszerzeniem jezyka ˛ SQL wprowadzajacym ˛ możliwość programowania proceduralnego oraz wsparcie dla funkcji przetwarzajacych ˛ dane. Oprócz tego baza danych zapewnia wsparcie dla przechowywania dokumentów XML. Niestety jest to jedna z niewielu funkcji dostepnych ˛ w bogatszych wariantach, która została udostepniona ˛ bezpłatnie. Oprócz pozbawienia wersji darmowej możliwości wyszukiwania pełnotekstowego, modułu analitycznego, raportujacego ˛ oraz łatwości skalowania odmiana ta nie może korzystać ze wszystkich możliwości sprze˛ tu, na którym pracuje. Maksymalna wielkość bazy danych została ograniczona do 10GB, wykorzystanie pamieci ˛ operacyjnej do 1GB, zaś możliwość wykonywania obliczeń do czterech watków ˛ procesora [10]. 3.1.3. PostgreSQL PostgreSQL jest obiektowo-relacyjnym systemem zarzadzania ˛ bazami danych o otwartym kodzie źródłowym, który został zapoczatkowany ˛ w 1986 roku. Przez lata zdobył uznanie użytkowników na całym świecie oraz stał sie˛ jednym z głównych konkurentów Oracle Database [2]. Charakteryzuja˛ go możliwość stosowania wielu typów indeksów, wyzwalaczy, typów danych, a nawet jezyków ˛ programowania wykorzystywanych do pisania funkcji składowych. PostgreSQL zapewnia wsparcie dla zdecydowanej wie˛ kszości konstrukcji jezyka ˛ SQL zaproponowanych w standardzie SQL:2011 [11] oraz wielu innych ułatwiajacych ˛ tworzenie zapytań oraz schematu bazy danych [3]. 3.1.4. Wybrana baza danych Na system zarzadzania ˛ bazami danych, który został wykorzystany w trakcie tworzenia aplikacji wybrano PostgreSQL w wersji 9.3. Za wyborem tym przemawiały: — pełne wsparcie dla transakcyjności, — duża zgodność ze standardem SQL, w tym SQL:2011, — brak ograniczeń licencyjnych, — znaczaca ˛ liczba użytkowników zgromadzona wokół systemu gwarantujaca ˛ szybka˛ pomoc, 3.2. Warstwa prezentacji 10 — łatwość rozszerzania oraz administracji poprzez graficzne narzedzia. ˛ PostgreSQL w przeciwieństwie do SQL Server Express oraz Oracle Database Express Edition nie nakłada na użytkownika ograniczeń na maksymalny rozmiar bazy danych oraz stopień wykorzystania pozostałych zasobów sprzetowych. ˛ 3.2. Warstwa prezentacji Warstwa prezentacji jest cześci ˛ a˛ aplikacji odpowiedzialna˛ za wyświetlanie danych oraz komunikacje˛ z użytkownikiem. Od wyboru sposobu zarzadzania ˛ tym elementem systemu zależy nie tylko wyglad, ˛ lecz również wydajność oraz sposób tworzenia systemu. Szkielety warstwy prezentacji moga˛ narzucać programiście określone wzorce projektowe lub korzystanie z konkretnych jezyków ˛ programowania. Podstawowym podziałem szkieletów warstwy prezentacji jest miejsce wykonywania obliczeń majacych ˛ na celu ustalenie wygladu ˛ aplikacji. W zwiazku ˛ z tym kryterium dzielimy je na biblioteki strony serwerowej oraz strony klienckiej. W przypadku stosowania pierwszego podejścia serwer odpowiada za przetworzenie danych wprowadzanych przez użytkownika oraz reakcje˛ na jego zachowanie. Do zadań aplikacji pracujacej ˛ na serwerze należy ustalenie wpływu tych operacji na zmiane˛ prezentowanego wygladu ˛ oraz przekazanie wyniku jego modyfikacji przegladarce ˛ internetowej. Przegladarka ˛ wyświetla zmieniony widok użytkownikowi. W podejściu opartym na architekturze klienckiej cześć ˛ operacji może zostać wykonana bez interakcji z aplikacja˛ serwerowa. ˛ Dzieje sie˛ tak dzieki ˛ zastosowaniu j˛ezyków takich jak JavaScript, które służa˛ do dynamicznej zmiany struktury dokumentu html. Rozwiazanie ˛ to wpływa na mniejsze obcia˛żenie łacza ˛ sieciowego oraz zapewnia szybsza˛ modyfikacje strony w odpowiedzi na zachowanie użytkownika. 3.2.1. AngularJS AngularJS jest stosunkowo nowym szkieletem aplikacyjnym zaprezentowanym przez Google w 2009 roku. Projekt ten jest przedstawicielem podejścia gdzie przetwarzanie widoku odbywa sie˛ w przegladarce ˛ internetowej użytkownika. Na rysunku 3.1 przedstawiony jest gwałtowny wzrost zainteresowania fraza˛ AngularJS w ostatnich latach. Rysunek 3.1: Zainteresowanie fraza˛ “AngularJS” [5] Celem AngularJS jest przezwycie˛ żenie niedoskonałości jezyka ˛ HTML polegaja˛ cych na niewielkim wsparciu dla dynamicznie zmieniajacej ˛ sie˛ zawartości. Twórcy 3.2. Warstwa prezentacji 11 projektu jako rozwiazanie ˛ proponuja˛ zestaw autorskich znaczników oraz atrybutów, które przeznaczone sa˛ do wykorzystania wewnatrz ˛ plików *.html. Zastosowanie tych elementów pozwala na deklaratywne projektowanie widoków, które automatycznie zmieniaja˛ sie˛ w odpowiedzi na modyfikacje modelu, z którym sa˛ połaczone. ˛ Dzi˛eki skorzystaniu z tych komponentów możliwe jest budowanie aplikacji zgodnie ze wzorcem Model-Widok-Kontroler. Aplikacje takie charakteryzuja˛ sie˛ luźnymi powiazaniami ˛ pomie˛ dzy widokami, a logika˛ biznesowa˛ oraz łatwiej jest w nich wykorzystać proces testowania jednostkowego. AngularJS jest łatwo rozszerzalny o dodatkowe moduły, które programista może pisać samodzielnie. Komponenty te moga˛ dostosowywać możliwości szkieletu do potrzeb autora aplikacji. W szczególności możliwe jest przyłaczanie ˛ zestawów klas CSS takich jak Bootstrap, które standaryzuja˛ wyglad ˛ wszystkich elementów widoku. Istnieje również możliwość tworzenia własnych znaczników, których używanie w trakcie deklarowania widoku ułatwia jego późniejsze zrozumienie i modyfikacje. Dane pomie˛ dzy aplikacja˛ serwerowa, ˛ a kliencka˛ wymieniane sa˛ w formacie JSON (JavaScript Object Notation). Modyfikacje danych w modelu przechowywanym w przegladarce ˛ użytkownika sa˛ automatycznie propagowane i wyświetlane. Jedna˛ z najciekawszych funkcji AngularJS jest wbudowany odpowiednik wstrzykiwania zależności. Możliwe jest zarejestrowanie komponentów, które szkielet bedzie ˛ potem przekazywał do wywoływanych metod. Programowanie w AngularJS wymaga od programisty znajomości JavaScript, CSS, HTML oraz Javy. 3.2.2. Vaadin Vaadin jest szkieletem tworzenia aplikacji internetowych, którego historia siega ˛ 2002 roku. Poczatkowo ˛ był zalewie zestawem narzedzi ˛ majacych ˛ ułatwiać prace˛ programistom firmy IT Mill. Z czasem projekt urósł do rozmiarów pełnoprawnego szkieletu aplikacyjnego. W 2007 roku porzucono koncepcje˛ własnego modułu wyświetlajacego ˛ interfejs użytkownika na rzecz Google Web Toolkit (GWT ). Jednocześnie udoste˛ pniono kod źródłowy i umożliwiono jego modyfikacje. W maju 2009 roku zmieniono nazwe˛ szkieletu na Vaadin. Od tego momentu można zaobserwować rosnace ˛ zainteresowanie tym rozwiazaniem, ˛ które ustabilizowało sie˛ w roku 2012. Rysunek 3.2: Zainteresowanie fraza˛ “Vaadin” [4] 3.2. Warstwa prezentacji 12 Rysunek 3.2 przedstawia zainteresowanie fraza˛ Vaadin od momentu wykorzystania jej jako nazwy szkieletu aplikacyjnego do lipca 2014 roku. Architektura Rozważania na temat architektury Vaadina silnie wia˛ża˛ sie˛ z GWT. Można wyróżnić dwa podstawowe moduły: — silnik po stronie klienta (ang. Client Side Engine - CSE), — cze˛ ść serwerowa. ˛ Dzie˛ ki wbudowanemu w GWT kompilatorowi Javy do JavaScript otrzymywany jest zestaw klas tworzacych ˛ CSE. Klasy umieszczone w pakiecie client tłumaczone sa˛ na JavaScript, by naste˛ pnie być uruchamianymi w przegladarce ˛ użytkownika. Pakiet server służy do przetrzymywania odpowiedników klas z pakietu client. Odpowiedniki tworzone sa˛ po stronie serwera aplikacyjnego. Komunikacja miedzy ˛ dwiema stronami wykorzystuje protokoły AJAX oraz RPC. Niezwykle istotne jest to, że podział na cześć ˛ serwerowa i kliencka˛ jest ukryty przed programista. ˛ Nie musi on posiadać szczegółowej wiedzy na temat zachodzacej ˛ wymiany danych, żeby tworzyć aplikacje [17]. Możliwe jest tworzenie własnych komponentów bed ˛ acych ˛ elementami interfejsu użytkownika. Dodatki Vaadin Directory powstało w 2010 roku. Jest to repozytorium dodatków, które można dołaczać ˛ do aplikacji tworzonych z wykorzystaniem szkieletu Vaadin. Celem utworzenia zbioru była che˛ ć ułatwienia tworzenia, znajdowania, integrowania oraz kupowania dodatków [14]. Każdy programista ma prawo utworzenia oraz zamieszczenia swojego dodatku z możliwościa˛ wyboru licencji oraz ceny. Zdecydowana wiekszość ˛ dodatków jest darmowa. Obecnie w repozytorium znajduje sie˛ ponad 450 dodatków podzielonych na naste˛ pujace ˛ kategorie: — komponenty UI (ang. UI Components), — komponenty danych (ang. Data Components), — motywy (ang. Themes), — narze˛ dzia (ang. Tools), — poboczne (ang. Miscellaneous) [12]. Olbrzymia liczba doste˛ pnych dodatków, ich różnorodność oraz łatwość integracji sa˛ jednym z czynników wpływajacych ˛ na popularność Vaadin. 3.2.3. Wybrany szkielet warstwy prezentacji Wybór szkieletu odpowiedzialnego za prezentacje˛ danych był jedna˛ z najważniejszych decyzji projektowych. Od tego elementu aplikacji w dużym stopniu zależy dobór bibliotek odpowiedzialnych za pozostałe moduły. Rozważane były AngularJS i Vaadin bed ˛ ace ˛ przedstawicielami skrajnie różnych podejść do tworzenia interfejsu graficznego. AngularJS opera sie˛ na tworzeniu i modyfikowaniu grafiki po stronie klienta zaś Vaadin po stronie serwera aplikacyjnego. Jako szkielet warstwy prezentacji wybrano Vaadin motywujac ˛ to: 3.3. Mapowanie obiektowo-relacyjne 13 — Duża˛ liczba˛ wbudowanych komponentów gotowych do wykorzystania, które znaczaco ˛ przewyższaja˛ możliwościami podstawowe elementy generowane poprzez HTML doste˛ pne w AngularJS. — Brakiem konieczności znajomości JavaScript, który jest wymagany podczas pracy z AngularJS. — Podejściem serwerowym ułatwiajacym ˛ zapewnienie bezpieczeństwa. — Bogatym zbiorem doste˛ pnych dodatków, które w znaczacy ˛ sposób moga˛ ułatwić prace programistyczna. ˛ — Preferencjami autora pracy, pragnacego ˛ zapoznać sie˛ z nieznanym szkieletem aplikacyjnym. W przeciwieństwie do AngularJS, Vaadin w dużym stopniu wpływa na warstwe˛ logiki biznesowej aplikacji. Jego komponenty maja˛ bezpośrednie odwzorowanie w cz˛eści serwerowej aplikacji, zaś generowanie widoku nie jest tak dokładnie odseparowane od pozostałej cze˛ ści aplikacji jak w AngularJS. 3.3. Mapowanie obiektowo-relacyjne Java jest obiektowym je˛ zykiem programowania. Prowadzi to do niekompatybilności typów pomie˛ dzy aplikacja˛ operujac ˛ a˛ na obiektach, a systemem zarzadzania ˛ baza˛ danych opartym na tabelach. Jest to powszechny problem i zaproponowano wiele sposobów jego zwalczania. Rozwiazaniem ˛ łatwo dostepnym ˛ oraz niezwykle popularnym jest skorzystanie z techniki odwzorowywania obiektowo-relacyjnego, której zadaniem jest konwersja danych pomiedzy ˛ aplikacja, ˛ a baza˛ danych. 3.3.1. Java Persistence API Java Persistence API (JPA) jest oficjalnym standardem przekształcania informacji z podejścia obiektowego do relacyjnego. Należy on do platformy Java Enterprise Edition (JEE). JPA jest specyfikacja˛ działania, zaś zadaniem dostawców jest stworzenie bibliotek oraz zagwarantowanie poprawności ich działania. Istnieje wiele implementacji tego standardu m.in. Hibernate, TopLink oraz OpenJPA. W skład specyfikacji wchodzi również jezyk ˛ JPQL. Dzieki ˛ niemu możliwe jest pobieranie danych bez znajomości struktury relacyjnej oraz bez konieczności tworzenia kwerend SQL, które moga˛ różnić sie˛ w zależności od zastosowanej bazy danych. W JPA programista definiuje klasy domenowe majace ˛ swoje odpowiedniki w encjach relacyjnych. Poprzez wykorzystanie mechanizmu adnotacji oraz analize˛ struktury klasy i jej zależności podejmowane sa˛ decyzje o poprawności modelu, sposobie odwzorowywania danych oraz możliwości ich modyfikacji. Przykładowa klasa domenowa opisana adnotacjami została przedstawiona na wydruku 3.1. 1 package pl . dziurdziak . easyReckoning . model . r o l e ; import java . u t i l . Set ; 5 import javax . persistence . ∗ ; import pl . dziurdziak . easyReckoning . model . user . User ; 10 @Entity @Table (name = " r o l e s " ) 3.3. Mapowanie obiektowo-relacyjne 14 public class Role { @Id @GeneratedValue private long id ; 15 @Column(name = " role_name " , length = 20, nullable = false , unique = true ) private String roleName ; @Version private int version ; 20 @ManyToMany( mappedBy = " r o l e s " ) private Set<User> users ; 25 } Wydruk 3.1: Przykładowa klasa domenowa Dzie˛ ki adnotacji @Entity klasa zostaje uznana, za klase˛ należac ˛ a˛ do modelu dziedziny. @Table określa nazwe˛ odpowiadajacej ˛ klasie tabeli bazodanowej. Pozostałe adnotacje sa˛ wykorzystywane do definiowania kolumn, ich własności oraz powiaza ˛ ń do innych obiektów. Szczególna˛ funkcje˛ pełni adnotacja @Version, która˛ oznaczane jest pole potrzebne do zastosowania strategii optymistycznego blokowania (ang. Optimistic locking) rekordów. Adnotacje te sa˛ odczytywane i sprawdzane przez biblioteke˛ implementujac ˛ a˛ standard JPA podczas uruchamiania aplikacji. Dzieki ˛ nim możliwe jest utworzenie kontekstu niezbe˛ dnego do pracy z baza˛ danych. 3.3.2. Hibernate Historia Hibernate sie˛ ga 2001 roku. Już wtedy zaobserwowano potrzebe˛ istnienia łatwej w użytkowaniu oraz bogatej w możliwości biblioteki oferujacej ˛ funkcje˛ mapowania obiektowo-relacyjnego. Tym samym proces powstawania Hibernate o pi˛eć lat wyprzedził pierwsza˛ wersje˛ specyfikacji JPA, która w dużej cześci ˛ została oparta na jego sposobie działania [15]. Hibernate w pełni implementuje standard JPA zapewniajac ˛ jednocześnie dodatkowe funkcjonalności. W szczególności dostarcza on je˛ zyk HQL be˛ dacy ˛ nadzbiorem JPQL. Hibernate jest jednym z najpopularniejszych narzedzi ˛ odwzorowywania obiektowo-relacyjnego. 3.3.3. EclipseLink EclipseLink wywodzi sie˛ od projektu TopLink zaś historia tego siega ˛ pomysłu realizowanego w latach dziewiećdziesi ˛ atych ˛ w jezyku ˛ Smalltalk. Nieco później powstała wersja dla je˛ zyka Java, a cała inicjatywa została przejeta ˛ przez firme˛ Oracle. W 2006 roku projekt TopLink został wzorcowa˛ implementacja˛ standardu JPA. Po krótkim okresie rozwoju firma Oracle udostepniła ˛ kod źródłowy oraz przekazała go Eclipse Foundation. Tym sposobem powstał EclipseLink, który rozwijany jest do tego momentu. 3.4. Wstrzykiwanie zależności 15 Podobnie jak Hibernate, EclipseLink oferuje funkcjonalności daleko wykraczajace ˛ poza standard JPA. Wśród nich można znaleźć wsparcie dla pamieci ˛ podrecz˛ nej (ang. cache), rozszerzona˛ składnie˛ jezyka ˛ JPQL oraz dodatkowe możliwości w tworzeniu zapytań. 3.3.4. Wybrane rozwiazanie ˛ Jako sposób doste˛ pu do danych wybrano standard JPA wspierany przez JPAContainer. JPAContainer jest dodatkiem do Vaadina umożliwiajacym ˛ tabelom pobieranie danych bezpośrednio z bazy danych. Konieczny był jeszcze wybór implementacji standardu. Z uwagi na da˛żenie do jak najrzadszego wykorzystywania funkcjonalności typowych tylko dla jednej implementacji była to decyzja o marginalnym znaczeniu. Nie chciano uzależnić działania projektowanego systemu od żadnej biblioteki służacej ˛ mapowaniu obiektowo-relacyjnemu. Zdecydowano sie˛ na Hibernate ponieważ jest to projekt o ugruntowanej pozycji na rynku, do którego można znaleźć olbrzymia˛ liczbe˛ materiałów pomocniczych. 3.4. Wstrzykiwanie zależności Wie˛ kszość obecnie tworzonego oprogramowania ma za zadanie wspieranie procesów zachodzacych ˛ w rzeczywistym świecie. Procesy te sa˛ zmienne, w zwiazku ˛ z czym raz napisane aplikacje wymagaja˛ późniejszych aktualizacji. Cz˛esto prowadzi to do sytuacji, w których najkosztowniejszym etapem dostarczania oprogramowania jest jego utrzymanie oraz modyfikacje majace ˛ na celu nada˛żanie za zachodza˛ cymi zmianami [18]. W drodze niwelowania tych kosztów wprowadzono wiele metodyk programowania oraz narze˛ dzi majacych ˛ ułatwić wprowadzanie zmian. Na szczególna˛ uwage˛ zasługuje tutaj idea programowania sterowanego testami (ang. Test-driven development), które w znaczacy ˛ sposób upraszcza modyfikacje˛ poprzez możliwość zagwarantowania poprawności działania niezmienianych elementów systemu. Jednym z czynników majacy ˛ najwiekszy ˛ wpływ na koszt wprowadzania zmian oraz na zwie˛ kszenie trudności testowania aplikacji sa˛ ścisłe powiazania ˛ pomiedzy ˛ klasami. Zaproponowano kilka sposobów majacych ˛ służyć jako rozwiazania ˛ tego problemu m.in.: — wzorzec fabryki, — wzorzec lokalizator serwisów (ang. Service Locator)), — wstrzykiwanie zależności (ang. Dependency Injection - DI). Najlepszym rozwiazaniem ˛ jest wstrzykiwanie zależności oferujace ˛ najwie˛ ksza˛ elastyczność, możliwości oraz wygode˛ programowania. Wzorzec lokalizator serwisów zaś coraz cze˛ ściej uznawany jest za antywzorzec [19]. Podejście be˛ dace ˛ esencja˛ wstrzykiwania zależności najłatwiej opisać jako oddelegowanie tworzenia oraz zarzadzania ˛ zależnościami obiektów do oddzielnego komponentu aplikacji. Element ten, zwany kontenerem, odpowiedzialny jest za dostarczenie odpowiednio zainicjalizowanych obiektów w odpowiedzi na żadania ˛ przychodzace ˛ z innych cze˛ ści aplikacji. Rozwiazanie ˛ to spełnia paradygmat odwrócenia sterowania (ang. Inversion of Control - IoC). Rozwiazanie ˛ to prowadzi do luźnych powiaza ˛ ń pomiedzy ˛ klasami, gdyż te zazwyczaj uzależnione sa˛ tylko od interfejsów specyfikujacych ˛ zachowanie, a nie od 16 3.4. Wstrzykiwanie zależności klas je implementujacych. ˛ Dzieki ˛ temu możliwe jest bezproblemowe testowanie klas w izolacji od pozostałych składników tworzonego systemu. Możliwe jest również wprowadzanie zmian, o ile nie wpływaja˛ one na modyfikacje˛ kontraktu klasy zawieranego poprzez implementowanie interfejsów. Dzie˛ ki oddelegowaniu zadania dostarczania obiektów do zewnetrznego ˛ komponentu programista nie musi już śledzić wszystkich odwołań do obiektów modyfikowanej klasy w istniejacym ˛ systemie, gdyż o poprawność ich inicjalizacji dba kontener. Do najpopularniejszych kontenerów wstrzykiwania zależności należa: ˛ — Spring, — Guice, — PicoContainer i NanoContainer, — Weld. 3.4.1. Spring Spring Framework jest szkieletem aplikacyjnym, którego jednym z głównym komponentów jest kontener IoC. Projekt ten ma ugruntowana˛ pozycje˛ na rynku rozwiaza ˛ ń technologicznych. Pierwsza wersja została wydana już w 2002 roku. Wraz z rozwojem do podstawowego modułu przyłaczano ˛ coraz wiecej ˛ komponentów. Obecnie Spring może wspomagać wiekszość ˛ realizowanych przez typowe aplikacje zadań. Poczatkowo ˛ konfiguracja modułu wstrzykiwania zależności odbywała si˛e poprzez plik konfiguracyjny zazwyczaj nazywany Beans.xml. Szkielet takiego pliku przedstawiony jest na wydruku 3.2. Programista w obrebie ˛ znacznika <beans> definiuje kolejne beany be˛ dace ˛ obiektami Javy. W obrebie ˛ znacznika <bean> znajduja˛ sie˛ też szczegółowe instrukcje o tym jak należy zainicjalizować żadany ˛ obiekt. Każdy bean zostaje nazwany co umożliwia wykorzystanie go przy definicji nastep˛ nych. Podejście to charakteryzuje sie˛ olbrzymimi możliwościami konfiguracyjnymi. 1 5 <?xml version= " 1.0 " encoding= "UTF−8" ?> <beans xmlns= " h t t p : //www. springframework . org/schema/beans " xmlns:xsi= " h t t p : //www.w3. org/2001/XMLSchema−instance " xsi:schemaLocation= " h t t p : //www. springframework . org/schema/beans h t t p : //www. springframework . org/schema/beans/spring−beans . xsd " > <bean id= " . . . " class= " . . . " > < !−− i n s t r u k c j e i n i c j a l i z a c j i obiektu </bean> −−> 10 </beans> Wydruk 3.2: Szkielet pliku Beans.xml Wraz z rozwojem je˛ zyka Java oraz popularyzacja˛ korzystania z adnotacji twórcy szkieletu Spring wprowadzili alternatywna˛ wersje˛ definiowania przebiegu wstrzykiwania zależności przedstawiona˛ na wydruku 3.3. W podejściu tym konfiguracja z pliku Beans.xml została przeniesiona do klas Javy oznaczonych adnotacjami @Configuration. Do głównych zalet tego rozwiazania ˛ należa˛ bezpieczeństwo typowania oraz wykrywanie problemów już na etapie kompilacji aplikacji. 1 @Configuration public class ConfigurationClass { 3.4. Wstrzykiwanie zależności @Bean( initMethod = " i n i t " ) @Scope ( " prototype " ) public SomeBean createBean ( ) { // t u t a j dokonywana j e s t i n i c j a l i z a c j a obiektu } 5 10 17 } Wydruk 3.3: Konfiguracja metody tworzacej ˛ bean Przykład wykorzystania wstrzykiwania zależności skonfigurowanego za pomoca˛ pliku beans.xml przedstawiony jest na wydruku 3.4. 1 import org . springframework . beans . f a c t o r y . BeanFactory ; import org . springframework . context . ApplicationContext ; import org . springframework . context . support . ClassPathXmlApplicationContext ; 5 public class Main { public static void main ( String [ ] args ) { ApplicationContext context = new ClassPathXmlApplicationContext ( "META−INF/beans . xml " ) ; BeanFactory f a c t o r y = context ; MyBean t e s t = (MyBean) f a c t o r y . getBean ( "myBean" ) ; } } 10 Wydruk 3.4: Przykład wykorzystania wstrzykiwania zależności w Spring Spring Framework jest dojrzałym szkieletem oferujacym ˛ wiele możliwości rozszerzajacych ˛ samo poje˛ cie wstrzykiwania zależności. Należy do nich miedzy ˛ innymi programowanie aspektowe poprzez wykorzystanie jezyka ˛ AspectJ. 3.4.2. Context Dependency Injection Context Dependency Injection (CDI) jest jedna˛ ze specyfikacji należacych ˛ do platformy JEE. Wzorcowa˛ implementacja˛ tego standardu jest Weld, bed ˛ acy ˛ zintegrowany z wieloma doste˛ pnymi na rynku serwerami aplikacyjnymi. CDI zawiera nie tylko opis działania wstrzykiwania zależności w Javie lecz jednocześnie specyfikuje zestaw usług majacych ˛ za zadanie znaczace ˛ ułatwienie programowania w środowisku JEE. Najważniejszym poje˛ ciem zwiazanym ˛ ze wstrzykiwaniem zależności w CDI jest zakres (ang. scope). Proces tworzenia, wykorzystywania oraz usuwania obiektów określa sie˛ mianem cyklu życia obiektu. Obiekty różnia˛ sie˛ od siebie długościa˛ swego istnienia oraz okresami przydatności. By poradzić sobie z tym problemem kontener musi posiadać informacje o cyklu życia obiektów, by w odpowiedni sposób zajmować sie˛ ich tworzeniem oraz usuwaniem. Cykl życia obiektu został powiazany ˛ z zakresami. Standard CDI definiuje nastepuj ˛ ace ˛ zakresy: — żadania ˛ (ang. request), — sesji (ang. session), — aplikacji (ang. application), którego odpowiednikiem jest singleton, — zależny (ang. dependend), zakres domyślny, — konwersacji (ang. conversation). 3.4. Wstrzykiwanie zależności 18 Każdy zakres ma określona˛ długość. Po rozpoczeciu ˛ zakresu, pierwsze żadania ˛ obiektów klas o danym cyklu życia bed ˛ a˛ skutkowały ich zainicjalizowaniem. Gdy nastapi ˛ zakończenie zakresu powiazane ˛ z nim obiekty klas nie bed ˛ a˛ już wiecej ˛ wstrzykiwane. Oprócz wstrzykiwania zależności CDI umożliwia programowanie aspektowe poprzez zastosowanie wzorca dekorator, oraz sposobności przechwytywania wywołań metod wstrzyknie˛ tych obiektów. CDI wspiera architekture˛ aplikacji opartych na zdarzeniach dostarczajac ˛ szyne˛ zdarzeń (ang. event bus). Konfigurowanie sposobu przekazywania obiektów zdarzeń odbywa sie˛ poprzez mechanizm adnotacji. Przykład obrazujacy ˛ zalety korzystania z CDI został przedstawiony na wydruku 3.5. W momencie żadania ˛ obiektu klasy Example kontener CDI stworzy go wykorzystujac ˛ do tego konstruktor oznaczony adnotacja˛ @Inject. CDI zadba również o odpowiednie przekazania parametrów do konstruktora. Po inicjalizacji zostanie wywołana metoda oznaczona za pomoca˛ @PostConstruct. Tak utworzony obiekt zostanie zwrócony do komponentu, który go potrzebuje. 1 public class Dependent { } public class Example { 5 private Dependent dependent ; @Inject public Example ( Dependent dependent ) { this . dependent = dependent ; } 10 @PostConstruct private void i n i t ( ) { } 15 } Wydruk 3.5: Przykład wykorzystania CDI Bardzo ważna˛ funkcja˛ CDI jest możliwość przechwytywania wywołań metod. Działanie to można wykorzystać miedzy ˛ innymi do automatycznego rejestrowania wywołań, otwierania transakcji bazodanowych oraz sprawdzania uprawnień użytkownika. Aby skorzystać z tych możliwości należy wykonać nastepuj ˛ ace ˛ kroki: — Utworzenie adnotacji, której obecność przy metodzie bedzie ˛ sygnalizowała, że wywołanie powinno być przechwycone. — Utworzenie klasy, której metoda oznaczona za pomoca˛ adnotacji AroundInvoke ma zostać uruchomiona podczas próby wywołania przechwytywanej metody. — Oznaczenie metod lub klas utworzona˛ adnotacja, ˛ by odpowiednie funkcje były przechwytywane. 3.4.3. Wybrany kontener wstrzykiwania zależności Jako komponent odpowiedzialny za wstrzykiwanie zależności wybrano CDI, a decyzje˛ o doborze implementacji uzależniono od wybranego serwera aplikacyjnego, którego zadaniem be˛ dzie jej dostarczenie. 3.5. Serwer aplikacyjny 19 Spring mimo swych oczywistych zalet takich jak olbrzymia popularność, łatwość konfiguracji, duże możliwości został odrzucony z uwagi na konieczność uzależnienia aplikacji od biblioteki w sytuacji gdy istnieje standard platformy Java EE be˛ dacy ˛ jej odpowiednikiem. Oprócz tego za wyborem CDI przemawiaja: ˛ — Dodatki Vaadin CDI oraz CDI Properties dostepne ˛ dla Vaadina, które ułatwiaja˛ integracje˛ z CDI oraz wprowadzaja˛ udogodnienia polegajace ˛ na automatycznym budowaniu komponentów interfejsu graficznego. — Możliwość programowania aspektowego. — Niewielka ilość konfiguracji potrzebnej do uruchomienia biblioteki. 3.5. Serwer aplikacyjny Serwer aplikacyjny jest środowiskiem, w którym działaja˛ aplikacje napisane zgodnie z architektura˛ JEE. Oprócz zapewniania możliwości pracy aplikacjom serwer zajmuje sie˛ zarzadzaniem ˛ transakcjami bazodanowymi, utrzymywaniem poła˛ czeń do zewne˛ trznych zasobów oraz dostarczaniem implementacji standardów JEE. Oddelegowanie dostarczania implementacji specyfikacji JEE sprawia, że aplikacje w wie˛ kszym stopniu skupione sa˛ na działaniach biznesowych oraz gwarantuje możliwość przenoszenia ich pomiedzy ˛ różnymi serwerami. Wybranie serwera aplikacyjnego jako środowiska pracy aplikacji zapewnia możliwość łatwego zarzadzania ˛ zasobami konsumowanymi przez aplikacje˛ oraz znaczaco ˛ zwie˛ ksza możliwości skalowania. Do zalet serwerów aplikacyjnych należa: ˛ — konfiguracja w jednym miejscu, — zwie˛ kszona wydajność, — możliwość skalowania, — bezpieczeństwo, — zarzadzanie ˛ transakcjami. Na rynku istnieje wiele serwerów różniacych ˛ sie˛ miedzy ˛ soba˛ wydajnościa, ˛ poziomem skomplikowania, wersjami specyfikacji, które wspieraja˛ oraz doborem implementacji wymaganych standardów. 3.5.1. GlassFish GlassFish jest system oferowanym przez firme˛ Oracle. Pierwsza wersja tego serwera aplikacyjnego została wydana w 2006 roku. Obecnie na rynku dostepna ˛ jest wersja czwarta w pełni wspierajaca ˛ standard Java EE 7, którego jest ona wzorcowa˛ implementacja. ˛ Serwer ten do niedawna rozpowszechniany był w dwóch wersjach: darmowej oraz komercyjnej. Jednak najnowsza wersja serwera nie zostanie obj˛eta komercyjnym wsparciem. GlassFish jest obecnie drugim najpopularniejszym serwerem w pełni zgodnym ze standardem JEE [7]. 3.5.2. WildFly WildFly jest serwerem aplikacyjnym rozwijanym przez Red Hat bed ˛ acym ˛ kontynuacja˛ serwera znanego jako JBoss. Do najważniejszych cech charakteryzujacych ˛ ten produkt należa˛ publicznie dostepny ˛ kod źródłowy oraz wykorzystanie otwartego oprogramowania jako implementacji standardów JEE. Dzieki ˛ skorzystaniu z 3.6. Moduł bezpieczeństwa 20 istniejacych, ˛ niezależnie rozwijanych rozwiaza ˛ ń serwer bardzo szybko adaptowany jest do uaktualnianych specyfikacji. 3.5.3. Wybrany serwer aplikacyjny W toku analizy technicznej zdecydowano, że serwerem aplikacyjnym, na którym zostanie uruchomiona aplikacja bedzie ˛ Wildfly w wersji 8.1. Oba rozważane serwery aplikacyjne w pełni spełniaja˛ standard Java EE 7 lecz wybrano Wildfly kierujac ˛ sie˛ krótkim czasem uruchomienia oraz niewielkim wykorzystaniu zasobów systemowych. Nie bez znaczenia było też wykorzystywanie przez ten serwer Hibernate jako implementacji standardu JPA. 3.6. Moduł bezpieczeństwa Zapewnienie bezpieczeństwa przechowywanych danych oraz kontrola możliwości wykonywania operacji przez użytkowników jest jednym z najważniejszych zadań programistów tworzacych ˛ aplikacje internetowe. Biblioteki wykorzystywane do zabezpieczenia aplikacji powinny być łatwo integrowalne, zapewniać możliwość mieszania danych oraz wspierać procesy zarzadzania ˛ uprawnieniami. Do zadań modułu bezpieczeństwa aplikacji należy: — Uwierzytelnianie – proces majacy ˛ na celu zweryfikowanie tożsamości użytkownika. — Autoryzacja – proces sprawdzajacy ˛ uprawnienia użytkownika żadaj ˛ acego ˛ dost˛epu do zasobu lub pragnacego ˛ wykonać chroniona˛ operacje. ˛ — Obsługa kryptografii – zestawu operacji zajmujacych ˛ sie˛ przekazywaniem oraz przechowywaniem informacji w bezpieczny sposób. 3.6.1. Spring Security Spring Security jest biblioteka˛ odpowiedzialna˛ za autoryzacje, ˛ uwierzytelnianie oraz zapewnianie bezpieczeństwa aplikacjom internetowym. Projekt powstał w 2003 pod nazwa˛ Acegi Security, by w 2007 roku zostać przemianowany na Spring Security. Biblioteka ta jest czesto ˛ wybierana jako szkielet bezpieczeństwa aplikacji korporacyjnych. Znana jest z olbrzymich możliwości konfiguracyjnych oraz łatwości integracji. Działanie Spring Security opiera sie˛ na możliwościach filtrów, które zostały zdefiniowane w standardzie JEE. Filtrami nazywamy komponenty wywoływane w celu obsłużenia przychodzacego ˛ żadania ˛ nim zostanie ono przekazane do elementu odpowiedzialnego za jego obsługe. ˛ Uruchomienie modułu Spring Security odbywa si˛e poprzez aktywacje filtra (przedstawiona˛ na wydruku 3.6). 1 5 10 <filter> < f i l t e r −name>springSecurityFilterChain</ f i l t e r −name> < f i l t e r −class> org . springframework . web . f i l t e r . DelegatingFilterProxy </ f i l t e r −class> </ f i l t e r > < f i l t e r −mapping> < f i l t e r −name>springSecurityFilterChain</ f i l t e r −name> <url−pattern>/∗</url−pattern> 3.6. Moduł bezpieczeństwa 21 </ f i l t e r −mapping> Wydruk 3.6: Fragment pliku web.xml aktywujacy ˛ filtr Spring Security Po aktywacji usługi konieczne jest jeszcze zdefiniowanie sposobu pobierania danych potrzebnych do autoryzacji i uwierzytelniania użytkowników. Spring Security zawiera wbudowane mechanizmy ułatwiajace ˛ integracje˛ z LDAP, OpenID, JAAS, Kerberos oraz wieloma innymi standardami. Oprócz elementów dostarczonych przez twórców szkieletu istnieja˛ gotowe rozwiazania ˛ programistyczne pozwalajace ˛ zintegrować biblioteke˛ z wieloma innymi systemami oraz protokołami. Jednym z mankamentów Spring Security jest silne uzależnienie od całej platformy Spring Framework. Istnieje możliwość wykorzystania tylko tego modułu lecz jest to podejście niezalecane. Przez długi czas moduł bezpieczeństwa był tworzony jako cze˛ ść szkieletu Spring i by w skorzystać z jego najbardziej zaawansowanych możliwości potrzebny jest dostep ˛ do pozostałych komponentów wspomagajacych ˛ m.in. programowanie aspektowe. 3.6.2. Apache Shiro Historia projektu Apache Shiro siega ˛ 2004 roku, w którym została stworzona biblioteka JSecurity be˛ daca ˛ jego bezpośrednim poprzednikiem. Powodem powstania prekursora była nieche˛ ć jego twórców do Java Authentication and Authorization Service (JAAS), be˛ dacego ˛ implementacja˛ mechanizmu autoryzacji oraz uwierzytelniania użytkowników wbudowana˛ w platforme˛ Java SE. Z czasem projekt został obj˛ety patronatem Apache Software Fundation w ramach programu inkubacyjnego. W lipcu 2010 roku udostepniona ˛ została pierwsza oficjalna wersja Apache Shiro [16]. Rysunek 3.3: Architektura Apache Shiro 3.6. Moduł bezpieczeństwa 22 Z grona swoich konkurentów Apache Shiro wyróżnia sie˛ przede wszystkim małym rozmiarem, szybkościa˛ działania, niewielkimi zależnościami od innych bibliotek oraz możliwościa˛ działania w środowisku nieserwerowym. Architektura Apache Shiro zbudowana jest wokół zarzadcy ˛ bezpieczeństwa (ang. Security Manager). Zazwyczaj jest on konfigurowany za pomoca˛ pliku bed ˛ acego ˛ zbiorem właściwości oraz wartości, odczytywanego podczas inicjalizacji aplikacji. Zarzadca ˛ bezpieczeństwa jest punktem dostepu ˛ do pozostałych funkcji biblioteki. Nadzoruje moduł uwierzytelniania (ang. Authenticator), moduł autoryzujacy ˛ (ang. Authorizer), zarzadc ˛ e˛ sesji (ang. Session Manager), pamieć ˛ krótkotrwała˛ (ang. cache) oraz dziedziny (ang. Realms). Dziedziny sa˛ zasobami wykorzystywanymi podczas procesów autoryzacji oraz uwierzytelniania. W odpowiedzi na przekazane tokeny z informacjami o tożsamości użytkownika lub podanymi przez niego danymi autoryzujacymi ˛ zwracaja˛ odpowiedź zawierajac ˛ a˛ informacje˛ o tym czy użytkownik poprawnie sie˛ zidentyfikował badź ˛ uzyskał doste˛ p do zasobu. Programiści tworzacy ˛ aplikacje˛ moga˛ tworzyć własne dziedziny oraz podłaczać ˛ je do Apache Shiro dzieki ˛ zapewnionej przez jego twórców swobodzie integracji. Dane, które wykorzystywane sa˛ w dziedzinach w zachodzacych ˛ procesach moga˛ być pobierane z dowolnego źródła. Najpopularniejszymi źródłami sa˛ pliki konfiguracyjne oraz bazy danych. Dane zalogowanego użytkownika przetrzymywane sa˛ w obiekcie sesji. Apache Shiro udoste˛ pnia specjalny komponent DAO, który umożliwia wykorzystanie biblioteki również w systemach nieserwerowych, gdy nie istnieje obiekt HttpSession. W pamie˛ ci krótkotrwałej przechowywane sa˛ wyniki ostatnich zapytań wykonanych przez dziedziny do zewnetrznych ˛ zasobów. Dzieki ˛ zapamietaniu ˛ rezultatów możliwe jest znaczace ˛ przyspieszenie działania w przypadku próby ponownego pobrania tych samych danych. Całość uzupełniona jest o obiektowy, łatwy w użytkowaniu interfejs zapewniajacy ˛ doste˛ p do funkcji kryptograficznych wbudowanych w maszyne˛ wirtualna. ˛ W momencie połaczenia ˛ z aplikacja˛ biblioteka umożliwia korzystanie zarówno z szyfrowania symetrycznego jak i różnorodnych funkcji skrótu. 3.6.3. OAuth OAuth jest standardem pozwalajacymi ˛ aplikacjom na limitowany doste˛ p do serwisów internetowych w imieniu użytkownika. Protokół ten powstał w 2006 roku. Obecnie doste˛ pna jest już druga wersja skupiajaca ˛ sie˛ na uproszczeniu przebiegu autoryzacji. Nim powstał OAuth jeśli użytkownik chciał przekazać aplikacji uprawnienia do serwisu zmuszony był udostepnić ˛ swój login i hasło. Skutkowało to oddaniem aplikacji pełni możliwości zarzadzania ˛ serwisem. Użytkownik zmuszony był zaufać intencjom twórców oraz zapewnieniom o nieszkodliwości oprogramowania. Protokół OAuth pozwala nie tylko na powierzenie limitowanego dostepu ˛ lecz jednocześnie zezwala na deklarowanie elementów serwisu, które maja˛ być objete ˛ pozwoleniem. Na wydruku 3.4 przedstawiono przebieg logowania do aplikacji z wykorzystaniem serwisu wspierajacego ˛ protokół OAuth. Nim zostanie wykonana ta operacja twórca aplikacji powinien zarejestrować ja˛ w serwisie poświadczajacym, ˛ by uzyskać unikalny klucz i sekret, które w dalszym procesie posłuża˛ do wygenerowania tokenu żadania. ˛ W momencie gdy użytkownik chce sie˛ zalogować pobierany jest 3.6. Moduł bezpieczeństwa 23 Rysunek 3.4: Przebieg uwierzytelniania z wykorzystaniem OAuth token żadania, ˛ który naste˛ pnie przesyłany jest wraz z przekierowaniem użytkownika na strone˛ serwisu. Serwis na podstawie tokenu ustala aplikacje, ˛ która chce uzyskać doste˛ p do danych oraz pyta użytkownika czy ten wyraża zgode˛ na ich udoste˛ pnienie. W przypadku odpowiedzi pozytywnej do aplikacji zwracana jest informacja, że token żadania ˛ został autoryzowany, a użytkownik zostaje ponownie przekierowany na strone˛ aplikacji. Dzieki ˛ posiadanemu tokenowi możliwe jest otrzymanie tokenu doste˛ pu, który zezwala na pobieranie danych potrzebnych do zalogowania. Przedstawiony tutaj proces przebiega podobnie również w sytuacji gdy dotyczy on nie logowania lecz doste˛ pu do innych zasobów lub możliwości wykonania operacji. Protokół OAuth wspierany jest miedzy ˛ innymi przez takie serwisy jak: — Facebook, — Dropbox, — Twitter, — LinkedIn, — Google. 3.6.4. Wybrany szkielet bezpieczeństwa Podje˛ to decyzje˛ , że proces zabezpieczania aplikacji bedzie ˛ wspierany przez Apache Shiro. Spring Security mimo swoich zalet takich jak popularność, łatwość konfiguracji i duże możliwości został odrzucony z powodu ścisłego powiazania ˛ z pozostałymi komponentami Spring Framework. Za Apache Shiro przemawiały niewielki rozmiar, szybkość działania, jasno zdefiniowana architektura oraz możliwość 3.7. Testowanie jednostkowe 24 integracji z pozostałymi elementami systemu. W toku analizy zauważono, że konieczne be˛ dzie dodanie warstwy łacz ˛ acej ˛ Apache Shiro z repozytorium użytkowników przetrzymywanym w bazie danych oraz stworzenie wsparcia dla standardu OAuth. 3.7. Testowanie jednostkowe Etap testowania jest niezwykle ważny w cyklu tworzenia aplikacji. Pozwala twórcy upewnić sie˛ czy produkt spełnia wymagania oraz sprawdzić jego zgodność z dokumentacja. ˛ Niestety odsuniecie ˛ etapu testów w czasie do momentu zakończenia fazy implementacyjnej skutkuje zwiekszonym ˛ kosztem modyfikacji oraz ryzykiem wprowadzenia innych błe˛ dów. By zapobiec tym niedogodnościom wprowadzono metode˛ tworzenia oprogramowania sterowana˛ testami (ang. Test Driven Development). Opiera sie˛ ona na tworzeniu testów jednostkowych sprawdzajacych ˛ działanie pojedynczych klas oraz metod aplikacji. Dzie˛ ki dużej liczbie testów jednostkowych błedy ˛ niskiego poziomu sa˛ szybko odkrywane oraz na bieżaco ˛ poprawiane. Wprowadzanie zmian do aplikacji obarczone jest mniejszym ryzykiem, ponieważ programista ma pewność, że jego modyfikacja nie wpłyne˛ ła na poprawność działania pozostałych elementów systemu. Wraz z koniecznościa˛ pisania dużej liczby testów jednostkowych zaistniała potrzeba zautomatyzowania procesu ich wykonywania. Powstało wiele szkieletów majacych ˛ spełnić to zadanie. 3.7.1. JUnit JUnit jest jednym ze szkieletów odpowiedzialnych za zautomatyzowane wykonywanie testów jednostkowych. Biblioteka ta jest jedna˛ z najcześciej ˛ wykorzystywanych podczas tworzenia projektów w jezyku ˛ Java. Należy ona do rodziny szkieletów xUnit. Prostota korzystania z JUnit jest jedna˛ z jego najwiekszych ˛ zalet. Konfiguracja testów jednostkowych jest tworzona z wykorzystaniem adnotacji. Przykład przedstawiony jest na wydruku 3.7. W notacji JUnit opisanie metody adnotacja˛ @Test oznacza, że metoda ta jest testem jednostkowym i powinna zostać wywołana podczas procesu testowania. Jeśli metoda zgłosi wyjatek ˛ test jednostkowy zostaje uznany za nieudany. Metoda oznaczona adnotacja˛ @Before zostanie wykonana przed każdym testem, zaś oznaczona za pomoca˛ @After po. Istnieje wiele innych adnotacji majacych ˛ na celu np. : — określenie momentu wywołania metod, — określenie klasy majacej ˛ wywołać test klasy, — ignorowanie testu, — zdefiniowanie parametrów do kolejnych wywołań metod testowych. 1 import static org . a s s e r t j . core . api . Assertions . assertThat ; import org . j u n i t . ∗ ; public class JUnitTest { 5 @Before public void setUp ( ) { 3.7. Testowanie jednostkowe 25 // . . . } 10 @Test public void testParsePln ( ) { assertThat ( false == false ) ; } 15 @After public void tearDown ( ) { // . . . } 20 } Wydruk 3.7: Przykład wykorzystania biblioteki JUnit 3.7.2. TestNG TestNG jest szkieletem testujacym ˛ silnie zainspirowanym działaniem JUnit oraz NUnit. Został stworzony w 2004 roku jako alternatywa dla JUnit. Wspiera nie tyko testy jednostkowe leczy równocześnie zapewnia możliwość testowania integracyjnego i funkcjonalnego. Podstawowe działania przeprowadza sie˛ w sposób identyczny co w JUnit. TestNG dostarcza zestaw adnotacji o takich samych nazwach, które w identyczny sposób steruja˛ przebiegiem testowania. Zalety TestNG ujawniaja˛ sie˛ w momencie przeprowadzania testów parametryzowanych lub stosowania testowania sterowanego danymi (ang. data-driven testing). Szkielet wspiera również testowanie kodu wielowatkowego ˛ poprzez wsparcie dla jednoczesnego uruchamiania wielu testów jednostkowych. Na wydruku 3.8 przedstawione jest wykorzystanie adnotacji @DataProvider ułatwiajacej ˛ testowanie sterowane danymi. Metoda testData jest uznawana za test jednostkowy dzie˛ ki obecności @Test. Funkcja ta zostanie uruchomiona wielokrotnie, gdyż jako jej parametry zostana˛ wykorzystane elementy macierzy zwróconej przez createData. Połaczenie ˛ rezultatu createData z danymi wejściowymi testData nast˛epuje poprzez wykorzystanie adnotacji @DataProvider oraz parametru dataProvider adnotacji @Test. 1 import org . testng . annotations . ∗ ; public class DataProviderTest { @DataProvider (name = " test1 " ) public Object [ ] [ ] createData ( ) { return new Object [ ] [ ] { { " Tekst−1" , new Integer ( 1 ) } , { " Tekst−4" , new Integer ( 4 ) } } ; } 5 10 @Test ( dataProvider = " test1 " ) public void testData ( String n1, Integer n2 ) { // . . . } 15 } Wydruk 3.8: Przykład wykorzystania adnotacji @DataProvder 3.8. Makietowanie 26 3.7.3. Wybrany szkielet testujacy ˛ Zdecydowano, że szkieletem testujacym ˛ wykorzystanym w aplikacji bedzie ˛ JUnit. Mimo wie˛ kszych możliwości oferowanych przez TestNG nie zdecydowano sie˛ na t˛e biblioteke˛ ponieważ nie zostana˛ one wykorzystane podczas tworzenia systemu. Za wybraniem JUnit przemawiał również fakt zaznajomienia autora niniejszej pracy z ta˛ biblioteka. ˛ 3.8. Makietowanie Jedna˛ z podstawowych idei testowania jednostkowego jest wykonywanie testów w izolacji od innych klas systemu informatycznego. W pewnych sytuacjach takie przeprowadzanie testów jest niezwykle trudne. Czesto ˛ przyczyna˛ sa˛ odniesienia do zewne˛ trznych zasobów, metod statycznych lub czasochłonnych obliczeń. Możliwe jest tworzenie prostych implementacji interfejsów z których korzystaja˛ klasy testowe lecz takie rozwiazanie ˛ jest czasochłonne oraz pozostawia możliwość popełnienia błe˛ du. W takiej sytuacji bezpieczniej jest skorzystać z biblioteki oferujacej ˛ automatyczne budowanie makiet, których zadaniem jest zastapienie ˛ odwołań do niepożadanych ˛ elementów systemu. 3.8.1. Mockito Mockito jest popularna˛ biblioteka˛ ukierunkowana˛ na ułatwienie tworzenia testów jednostkowych poprzez umożliwienie budowania makiet (ang. mock) obiektów. W Mockito utworzenie makiety odbywa sie˛ poprzez wywołanie statycznej metody mock lub poprzez skorzystanie z adnotacji @Mock wraz ze zmiana˛ klasy uruchamiajacej ˛ testy na MockitoJUnitRunner. 1 package pl . dziurdziak . easyReckoning . s e r v i c e . user ; import static org . mockito . Matchers . ∗ ; import static org . mockito . Mockito .when; 5 import import import import org . j u n i t . ∗ ; org . j u n i t . runner . RunWith ; org . mockito .Mock; org . mockito . runners . MockitoJUnitRunner ; import import import import pl . dziurdziak . easyReckoning . dto . s e t t i n g s . ChangePasswordDto ; pl . dziurdziak . easyReckoning . model . user . ∗ ; pl . dziurdziak . easyReckoning . u t i l s . errors . BusinessException ; pl . dziurdziak . easyReckoning . u t i l s . security . VaadinSecurityUtil ; 10 15 20 25 @RunWith ( MockitoJUnitRunner . class ) public class UserServiceTest { @Mock private UserDao userDao ; @Mock private VaadinSecurityUtil vaadinSecurityUtil ; @Mock private User currentUser ; private UserService userService ; @Before public void setUp ( ) { userService = new UserService ( userDao , 1 , vaadinSecurityUtil ) ; } 3.8. Makietowanie 27 @Test ( expected = BusinessException . class ) public void testChangePasswordOldNotCorrect ( ) { when ( userDao . findById ( eq (1L ) ) ) . thenReturn ( currentUser ) ; when ( currentUser . getPassword ( ) ) . thenReturn ( " oldHash " ) ; when ( vaadinSecurityUtil . hashPassword ( anyString ( ) , anyString ( ) ) ) . thenReturn ( " calculatedOldHash " ) ; 30 35 userService . changePassword ( new ChangePasswordDto ( " oldPass " , " newPass " , " newPass " ) ) ; } 40 } Wydruk 3.9: Przykład wykorzystania biblioteki Mockito W powyższym przykładzie skorzystano z adnotacji @Mock do inicjalizacji makiet. Nast˛epnie w metodzie oznaczonej adnotacja˛ @Before (wywoływanej przed każdym testem) tworzony jest obiekt klasy podlegajacej ˛ testowi. Utworzenie tego obiektu odbywa sie˛ poprzez przekazanie mu referencji do makiet dzieki ˛ czemu uniezależniony jest on od pozostałych klas systemu. W ramach testu wywoływane sa˛ statyczne metody when, które definiuja˛ działanie makiet w odpowiedzi na wywołania ich metod. Dopiero po określeniu zachowania makiet naste˛ puje wywołanie metody, której działanie jest testowane w teście jednostkowym. 3.8.2. EasyMock EasyMock jest biblioteka˛ Java konkurujac ˛ a˛ z Mockito. Oferuje bardzo podobne możliwości lecz różni sie˛ składnia˛ oraz sposobem prezentacji błedów. ˛ Na poniższym wydruku przedstawiony jest przykład wykorzystania biblioteki EasyMock. Należy zwrócić uwage, ˛ że definiowanie makiet jest równie proste jak w Mockito. Różnica wyste˛ puje w konieczności jawnego podania w jakiej fazie znajduja˛ si˛e aktualnie makiety. Po utworzeniu i podaniu oczekiwanych wywołań metod należacych ˛ do makiet konieczne jest odwołanie do funkcji replayAll. Weryfikacja nast˛epuje w momencie wywołania funkcji verifyAll. 1 public class EasyMockTest extends EasyMockSupport { private Collaborator c o l l a b o r a t o r ; ] private ClassTested classUnderTest ; 5 @Before public void setUp ( ) { classUnderTest = new ClassTested ( ) ; } 10 15 @Test public void addDocument ( ) { // faza tworzenia c o l l a b o r a t o r = createMock ( Collaborator . class ) ; classUnderTest . addListener ( c o l l a b o r a t o r ) ; // faza definiowania zachowania c o l l a b o r a t o r . documentAdded ( "New Document" ) ; replayAll ( ) ; 3.8. Makietowanie 28 20 // t e s t classUnderTest . addDocument ( "New Document" , new byte [ 0 ] ) ; // weryfikacja verifyAll ( ) ; 25 } } Wydruk 3.10: Przykład wykorzystania biblioteki EasyMock 3.8.3. Wybrana biblioteka makietujaca ˛ Na biblioteke˛ odpowiedzialna˛ za makietowanie obiektów wybrano Mockito. Charakteryzuje sie˛ ona czytelniejszym interfejsem niż EasyMock, a jej popularność gwarantuje możliwość znalezienia pomocy w przypadku wystapienia ˛ problemów z działaniem. 4. Projekt systemu 4.1. Architektura Przez lata tworzenia aplikacji inżynierowie oprogramowania zaproponowali wiele wzorców opisujacych ˛ podział aplikacji. Podczas tworzenia aplikacji graficznych jednym z najcze˛ ściej wykorzystywanych jest wzorzec MVC (ang. Model-View-Controller, pol. Model-Widok-Kontroler). Wzorzec MVC opiera sie˛ na podziale aplikacji na trzy moduły: — model, — widok, — kontroler. Model reprezentuje logike˛ aplikacji oraz przetrzymuje aktualny stan. Widok zajmuje sie˛ wizualizacja˛ modelu oraz interakcja˛ z użytkownikiem, ma możliwość modyfikacji modelu. Kontroler wspiera interakcje˛ z użytkownikiem oraz służy jako ich źródło. Pochodna˛ tego niezwykle popularnego wzorca jest MVP (ang. Model-View-Presenter, pol. Model-Widok-Prezenter) wystepuj ˛ acy ˛ w dwóch wariantach: — pasywny widok (ang. Passive view), — kontroler nadzorujacy ˛ (ang. Supervising Controller). Główna˛ różnica˛ mie˛ dzy MVC, a MVP jest mniejsza rola widoku, który w MVP służy wyłacznie ˛ jako wizualna reprezentacja modelu. Wszystkie akcje użytkownika przekazywane sa˛ do prezentera, który ma zwiekszon ˛ a˛ (w przeciwieństwie do MVC) wiedze˛ na temat budowy widoku i może powodować jego zmiany. Rysunek 4.1: Schemat wzorca MVP w wariancie kontrolera nadzorujacego ˛ 4.2. Podział pakietów 30 MVP charakteryzuje sie˛ możliwościa˛ łatwego testowania aplikacji z wykorzystaniem testów jednostkowych. Używajac ˛ makiet możliwe jest testowanie komponentów w odseparowaniu od pozostałych. Wada˛ MVP jest zwiekszona ˛ ilość kodu źródłowego (w stosunku MVC), która przypada na dodatkowa˛ komunikacje˛ miedzy ˛ widokiem, a prezenterem. Podczas tworzenia aplikacji wykorzystano wzorzec MVP w wariancie kontrolera nadzorujacego. ˛ Główna˛ motywacja˛ tej decyzji jest trudność w testowaniu graficznej cz˛eści aplikacji pisanej w szkielecie Vaadin. Przeniesienie wiekszości ˛ logiki aplikacji do warstwy prezentera pozwoliło na pełniejsze pokrycie kodu źródłowego testami. 4.2. Podział pakietów Rysunek 4.2: Diagram pakietów wewnatrz ˛ pakietu pl.dziurdziak.easyReckoning W aplikacji można wyróżnić nastepuj ˛ ace ˛ pakiety (przedstawione na rysunku 4.2): — pl.dziurdziak.easyReckoning.dto - pakiet przechowujacy ˛ klasy, których instancje służa˛ do komunikacji pomiedzy ˛ warstwami aplikacji — pl.dziurdziak.easyReckoning.model - pakiet przechowujacy ˛ klasy domenowe oraz DAO (ang. Data Access Object), których obiekty służa˛ jako źródło obiektów klas domenowych — pl.dziurdziak.easyReckoning.presenter - w tym pakiecie znajduja˛ sie˛ klasy należace ˛ do warstwy Prezenter — pl.dziurdziak.easyReckoning.service - zawiera implementacje˛ klas wykonuja˛ cych operacje˛ na modelu 4.3. Testowanie 31 — pl.dziurdziak.easyReckoning.utils - zawiera implementacje˛ klas narzedziowych ˛ szeroko wykorzystywanych w pozostałej cześci ˛ aplikacji. W szczególności zawiera podpakiety: — errors - definicje wyjatków, ˛ — localization - klasy odpowiadajace ˛ za wielojezyczność, ˛ — security - klasy modułu bezpieczeństwa, — validations - klasy odpowiadajace ˛ za walidacje˛ danych wprowadzanych przez użytkownika. — pl.dziurdziak.easyReckoning.view - zawiera klasy należace ˛ do warstwy Widoku. Szczególna˛ uwage˛ należy zwrócić na podpakiet ui zawierajacy ˛ definicje własnych elementów interfejsu użytkownika takich jak: nagłówek, stopka, nowe pola, okna modalne oraz kolumny tabel. 4.3. Testowanie Testowanie aplikacji składało sie˛ z dwóch elementów: — testów jednostkowych, — testów interfejsu graficznego wykonywanych przez programiste. ˛ W idealnym przypadku całość kodu źródłowego zostałaby pokryta poprzez testy jednostkowe. Niestety testowanie interfejsu użytkownika wymaga aplikacji działajacej ˛ w tle. Z uwagi trudności w sprawdzaniu tej cześci ˛ aplikacji twórcy szkieletu Vaadin udoste˛ pnili narze˛ dzie Vaadin TestBench zbudowane na bazie Selenium. Ma ono za zadanie umożliwić testowanie interfejsu użytkownika oraz jego współpracy z różnymi przegladarkami ˛ internetowymi. Narzedzie ˛ to jest płatne przez co nie może zostać użyte podczas tworzenia aplikacji. Jako próbe˛ zaradzenia problemowi podjeto ˛ decyzje˛ o testowaniu interfejsu użytkownika poprzez programiste˛ oraz objecie ˛ warstwy Prezentera testami jednostkowymi. Testy jednostkowe pokrywaja˛ kod nastepuj ˛ acych ˛ pakietów: — pl.dziurdziak.easyReckoning.presenter, — pl.dziurdziak.easyReckoning.service, — pl.dziurdziak.easyReckoning.utils. Każda testowana klasa ma odpowiadajac ˛ a˛ jej klase˛ testujac ˛ a, ˛ znajdujac ˛ a˛ sie˛ w tym samym pakiecie, lecz w innym folderze. Metody klas testujacych ˛ maja˛ za zadnie sprawdzać działanie klasy testowanej w zależności od przekazywanych parametrów oraz ustalonego stanu systemu. Przebieg procesu testowania jednostkowego przedstawiono na rysunku 4.3, zaś na wydruku 4.1 zaprezentowano przykładowa˛ klase˛ testujac ˛ a˛ wykorzystana˛ w aplikacji. 1 5 10 @RunWith ( MockitoJUnitRunner . class ) public class ResetUserPasswordPresenterTest { @Mock private @Mock private @Mock private @Mock private ResetUserPasswordView view ; UserService userService ; VaadinStaticUtils v a a d i n S t a t i c U t i l s ; TextBundle textBundle ; 4.3. Testowanie 32 private ResetUserPasswordPresenter resetUserPasswordPresenter ; @Before public void setUp ( ) { resetUserPasswordPresenter = new ResetUserPasswordPresenter ( view , userService , new BusinessErrorHandler ( textBundle , v a a d i n S t a t i c U t i l s ) , vaadinStaticUtils , textBundle ) ; } 15 20 @Test public void testReset ( ) { resetUserPasswordPresenter . resetPassword ( " userLogin " ) ; 25 v e r i f y ( userService , times ( 1 ) ) . resetPassword ( eq ( " userLogin " ) ) ; v e r i f y ( vaadinStaticUtils , times ( 1 ) ) . showSuccessNotification ( anyString ( ) , anyString ( ) ) ; 30 } } Wydruk 4.1: Klasa testujaca ˛ prezenter ResetUserPasswordPresenter 4.3. Testowanie Rysunek 4.3: Przebieg procesu testowania jednostkowego 33 4.4. Wyjatki ˛ 34 4.4. Wyjatki ˛ Wyjatki ˛ generowane przez elementy systemu zostały podzielone na dwa rodzaje: — biznesowe, — techniczne. Mianem wyjatków ˛ biznesowych określa sie˛ wszystkie klasy dziedziczace ˛ po klasie pl.dziurdziak.easyReckoning.utils.errors.BusinessException. Cecha˛ charakterystyczna˛ obiektów tych klas jest obowiazkowe ˛ przenoszenie wiadomości informuja˛ cej o powodzie zgłoszenia błe˛ du. Wyjatkami ˛ technicznymi określa sie˛ wszystkie wyjatki ˛ nie zaliczane do poprzedniej grupy. Wśród nich znajduja˛ sie˛ również wyjatki ˛ generowane przez biblioteki trzecie. Obsługa dwóch wymienionych wcześniej rodzajów wyjatków ˛ jest różna. Błedy ˛ biznesowe zwiazane ˛ sa˛ zazwyczaj z niepoprawnymi danymi podanymi przez użytkownika, badź ˛ próba˛ wykonania operacji niedozwolonej w danej chwili. Jako takie sa˛ wyjatkami, ˛ których obsłużenie czesto ˛ zapewnia możliwość dalszej pracy użytkownika nad aktualnie wykonywanym zadaniem. Błedy ˛ techniczne prowadza˛ do sytuacji, w których kontynuacja operacji przez użytkownika jest niemożliwa. Błe˛ dy biznesowe obsługiwane sa˛ na dwa sposoby: — wyświetlenie notyfikacji o błedzie ˛ - działanie wspierane przez klase˛ pl.dziurdziak.easyReckoning.utils.errors.BusinessErrorHandler, — przekierowanie do podstrony error, która może zawierać szczegółowe informacje o prawdopodobnej przyczynie błedu. ˛ W przypadku zgłoszenia wyjatku ˛ technicznego moduł nawigacyjny aplikacji przekierowuje użytkownika do podstrony error, która w sposób ogólny informuje o wystapieniu ˛ błe˛ du wewnatrz ˛ systemu. 4.5. Model logiczny Użytkownik (User) - Reprezentuje osobe˛ zarejestrowana˛ i uprawniona˛ do korzystania z aplikacji. Encja ta przechowuje nastepuj ˛ ace ˛ informacje o osobie: — sztuczny identyfikator (id), — unikalny login, — unikalny e-mail, — skrót hasła, — sól używana do konstruowania skrótu hasła, — date˛ rejestaracji, — czy konto zostało zablokowane. Encja Użytkownik połaczona ˛ jest z encjami Rola, Członek grupy, Znajomy, Zaproszenie do grupy oraz Zaproszenie do znajomych. Oprócz tego łaczy ˛ sie˛ ona z encjami be˛ dacymi ˛ typami operacji badź ˛ kont. Rola (Role) - Reprezentuje role pełniona˛ przez użytkownika w systemie bezpieczeństwa. Identyfikatorem roli jest jej nazwa, która musi być unikalna. Jest to jedyny atrybut tej encji. 4.5. Model logiczny 35 Rola jest połaczona ˛ z encjami Użytkownik oraz Uprawnienie. Uprawnienie (Permission) - Encja ta reprezentuje uprawnienie przypisane roli. Uprawnienie może oznaczać możliwość wykonania akcji lub dostep ˛ do zasobu przez użytkownika. Jedynym atrybutem encji Uprawnienie jest jej nazwa. Encja Uprawnienie jest połaczona ˛ z encja˛ Rola. Znajomy (Friend) - Encja ta reprezentuje fakt znajomości pomiedzy ˛ dwoma użytkownikami. Identyfikatorem encji jest sztuczne pole id, jednak kombinacja pól zapraszajacy ˛ oraz zapraszany powinna być unikalna. Encja Znajomy jest w podwójnym zwiazku ˛ z encja˛ Użytkownik. Jedno połaczenie ˛ dotyczy użytkownika zapraszajacego, ˛ drugie zapraszanego. Zaproszenie do znajomych (Friend request) - Encja reprezentuje fakt zaproszenia użytkownika, przez innego, do grona swoich znajomych. Encja posiada sztuczny identyfikator oraz nastepuj ˛ ace ˛ atrybuty: — zapraszajacy, ˛ — zapraszany, — wiadomość do zapraszanego, — status zaproszenia, — date˛ wysłania. Zaproszenie może znajdować sie˛ w nastepuj ˛ acych ˛ statusach: — nowe (new), — zaakceptowane (accepted), — odmówione (refused), — anulowane (cancelled). Encja Zaproszenie do znajomych łaczy ˛ sie˛ z encja˛ Użytkownik. Jedno połaczenie ˛ dotyczy użytkownika zapraszajacego, ˛ drugie zapraszanego. Grupa (Group) - Encja reprezentuje zbiór użytkowników. Grupa posiada sztuczny identyfikatora, nazwe, ˛ opis oraz admina. Adminem grupy jest jej założyciel, który automatycznie staje sie˛ członkiem grupy. Encja Grupa łaczy ˛ sie˛ z encja˛ Użytkownik. Jedno połaczenie ˛ dotyczy admina grupy, drugie jej członków. Zaproszenie do grupy (Group invitation) - Encja reprezentuje fakt zaproszenia użytkownika do członkostwa w grupie. Łaczy ˛ sie˛ z encja˛ Użytkownik informujac ˛ o zapraszajacym, ˛ zapraszanym oraz z encja˛ Grupa, której dotyczy zaproszenie. Operacja wirtualna (Virtual operation) - Encja ta reprezentuje fakt dokonania operacji finansowej przez użytkownika, który jest jej jedynym uczestnikiem. Posiada sztuczny identyfikator, kwote, ˛ nazwe, ˛ opis, date˛ operacji, date˛ utworzenia. Encja ta jest połaczona ˛ z encja˛ Konto wirtualne. Pożyczka (Loan) - Encja opisujaca ˛ przekazanie pieniedzy ˛ pomiedzy ˛ użytkownikami. 4.5. Model logiczny 36 Połaczona ˛ jest z encjami Użytkownik oraz Konto użytkownika. Operacja w parze (Pair operation) - Encja reprezentujaca ˛ operacje˛ finansowa˛ dokonana˛ przez pare˛ użytkowników. Od encji Pożyczka odróżnia ja˛ to, że kwota operacji jest dzielona pomiedzy ˛ uczestników w podanym przez tworzacego ˛ ja˛ użytkownika stosunku. Encja Operacja w parze powiazana ˛ jest z encjami Użytkownik oraz Konto użytkownika. Operacja wspólna (Shared operation) - Encja ta reprezentuje operacje˛ finansowa˛ dokonana˛ przez wie˛ cej niż jednego użytkownika. Kwota operacji dzielona jest po równo pomiedzy ˛ jej uczestników. Członków operacji ustala jej twórca. Dodajacy ˛ operacje˛ może zdefiniować ja˛ jako operacje˛ składkowa˛ podajac ˛ kwote˛ , która˛ wpłacili poszczególni uczestnicy. Encja powiazana ˛ jest z encja Użytkownik. Operacja grupowa (Group operation) - Encja ta reprezentuje fakt dokonania operacji finansowej przez grupe˛ użytkowników. Jest to szczególny przypadek operacji wspólnej, w której wszyscy członkowie należa˛ do jednej grupy. Twórca nie ma możliwość dodawania lub usuwania osób z operacji. Encja powiazana ˛ jest z encjami Użytkownik oraz Grupa. Konto użytkownika (User account) - Encja grupujaca ˛ operacje dokonywane pomi˛edzy użytkownikami. Posiada właściciela, bilans, nazwe˛ oraz użytkownika, z którym przeprowadzane sa˛ operacje˛ . Łaczy ˛ sie˛ z encjami Użytkownik oraz encjami operacji. Konto wirtualne (Virtual account) - Encja grupujaca ˛ operacje własne użytkownika. Posiada właściciela, bilans oraz nazwe. ˛ Łaczy ˛ sie˛ z encjami Użytkownik oraz Operacja wirtualna. 4.5. Model logiczny 37 Rysunek 4.4: Model logiczny (z uwagi na czytelność cześć ˛ encji została pominieta) ˛ 38 4.6. Model klas operacji 4.6. Model klas operacji Podczas tworzenia hierarchii klas operacji została wyodrebniona ˛ klasa abstrakcyjna Operation be˛ daca ˛ klasa˛ bazowa˛ dla pozostałych klas modelujacych ˛ operacje. Klasa Operation zawiera składowe wspólne dla wszystkich rodzajów operacji takie jak: — identyfikator, — kwota, — nazwa, — opis, — data operacji, — data utworzenia, — wersja (pole wykorzystywane przez JPA). Klasy dziedziczace ˛ po klasie Operation można podzielić na trzy typy: — operacje własne, — operacje pomie˛ dzy dwoma użytkownikami - podzielone na pożyczke, ˛ prosta˛ operacje˛ w parze oraz operacje˛ bed ˛ ac ˛ a˛ wynikiem operacji wspólnej, — operacje wspólne (pomie˛ dzy wieloma użytkownikami) - które moga˛ lecz nie musza˛ być powiazane ˛ z grupa. ˛ Zastosowane rozwiazanie ˛ przedstawione jest na diagramie 4.5. Rysunek 4.5: Model klas operacji 39 4.7. Model klas kont 4.7. Model klas kont Hierarchie˛ klas kont zamodelowano poprzez wykorzystanie klasy abstrakcyjnej Account zawierajacej ˛ pola wspólne dla dwóch rodzajów istniejacych ˛ kont: — użytkownika, — wirtualnych. Zastosowane rozwiazanie ˛ przedstawione jest na diagramie 4.6. Rysunek 4.6: Model klas kont 4.8. Model fizyczny 4.8.1. Operacje oraz konta Model fizyczny obrazujacy ˛ strukture˛ kont, operacji oraz ich wzajemne połacze˛ nia przedstawiony jest na diagramie 4.7. Klasy operacji zostały zamodelowane korzystajac ˛ z podejścia łaczonych ˛ tabel (ang. joined tables). Podejście to zakłada istnienie jednej tabeli głównej przechowujacej ˛ atrybuty wspólne dla wszystkich operacji oraz po jednej tabeli dla innych rodzajów operacji. Pozostałe tabele operacji połaczone ˛ sa˛ z podstawowa˛ relacja˛ współdzielenia klucza głównego (ang. shared primary key). Relacja ta polega na tym, że klucze główne tabel operacji sa˛ jednocześnie kluczami obcymi do identyfikatora tabeli podstawowej. Tabela˛ główna˛ jest tabela operations. Tworzac ˛ model klas kont zostało zastosowane odmienne podejście. Z uwagi na niewielki poziom skomplikowania hierarchii klas skorzystano z rozwiazania ˛ pojedynczej tabeli (ang. single table). W podejściu tym w jednej tabeli przechowywane sa˛ dane kont obu rodzajów. Ustalenie typu konta odbywa sie˛ na podstawie pola discriminator przechowujacego ˛ łańcuch znaków jednoznacznie go identyfikujacy. ˛ Konieczność wypełnienia pól charakterystycznych dla konta użytkownika zapewniana jest przez wyzwalacz. 40 4.8. Model fizyczny Rysunek 4.7: Model fizyczny operacji i kont 4.8. Model fizyczny 41 4.8.2. Moduł bezpieczeństwa Model fizyczny modułu bezpieczeństwa zaprezentowany jest na diagramie 4.8. W modelu tym każdy użytkownik może mieć przypisanych wiele ról, zaś każda rola może dawać wiele uprawnień. Kluczami głównymi ról oraz uprawnień sa˛ ich nazwy, co gwarantuje ich unikalność. Każde uprawnienie może być połaczone ˛ tylko z jedna˛ rola. ˛ Z uwagi na charakter połaczenia ˛ pomiedzy ˛ użytkownikami, a rolami została wprowadzona tabela łacz ˛ aca ˛ user_roles. Rysunek 4.8: Model fizyczny modułu bezpieczeństwa 5. Interfejs graficzny W rozdziale tym zostana˛ przedstawione fragmenty zaprojektowanego interfejsu użytkownika wraz z informacjami jakie wymagania stawiane aplikacji realizuja. ˛ Układ komponentów wyste˛ pujacych ˛ na zaprezentowanych przykładach został zadeklarowany w szablonach html. Rozwiazanie ˛ to ułatwiło tworzenie tego modułu systemu poprzez oddzielenie wygladu ˛ od logiki biznesowej. 5.1. Okno dodawania operacji grupowej Rysunek 5.1: Okno dodawania operacji grupowej Na rysunku 5.1 przestawiono okno dodawania operacji grupowej. Realizuje on wymaganie WF 27. W oknie oprócz podstawowych pól wyświetlona jest lista użytkowników bioracych ˛ udział w operacji zbudowana na podstawie przypisanej grupy. Pole wyboru ”Operacja składkowa” uaktywnia dodatkowa˛ kolumne˛ gdzie można podać wkład wniesiony przez każdego uczestnika. Przycisk ”Pokaż podglad” ˛ wyświetla tabele˛ operacji, które zostana˛ wygenerowane pomiedzy ˛ użytkownikami po zaakceptowaniu operacji. 5.2. Okno dodawania operacji w parze 43 5.2. Okno dodawania operacji w parze Na rysunku 5.2 przedstawione jest okno dodawania operacji pomiedzy ˛ para˛ użytkowników. Realizuje ono wymaganie WF 25. Niezaznaczone pole ”Podziel po połowie” aktywuje suwak ”Mój udział (%)”, w którym użytkownik może podać za jaka˛ cze˛ ść wartości operacji odpowiada. Lista wyboru ”Kto zapłacił” umożliwia wybór pomie˛ dzy wartościami: ”Ja”, ”Znajomy”, ”Dzielone”. W przypadku wybrania ostatniej opcji aktywuje sie˛ dodatkowe pole, w którym należy podać składke˛ aktualnego użytkownika. Rysunek 5.2: Okno dodawania operacji w parze 5.3. Ekran szczegółów grupy Rysunek 5.3: Ekran szczegółów grupy 5.4. Ekran szczegółów konta z użytkownikiem 44 Na rysunku 5.3 przedstawiono ekran szczegółów grupy, do której należy uwierzytelniony użytkownik. Realizuje on wymagania WF 13 oraz WF 14. W górnej cz˛eści znajduje sie˛ przycisk rozpoczynajacy ˛ proces dodawania operacji grupowej. Poniżej znajduje sie˛ lista członków grupy, przycisk służacy ˛ zapraszaniu nowych członków oraz lista aktualnie wysłanych zaproszeń. 5.4. Ekran szczegółów konta z użytkownikiem Rysunek 5.4: Ekran szczegółów konta z użytkownikiem Na rysunku 5.4 przedstawiono ekran szczegółów konta, które aktualny użytkownik posiada z innym. Realizuje on wymaganie WF 21. W górnej cześci ˛ ekranu znajduja˛ sie˛ podstawowe informacje o koncie oraz odnośnik do ekranu wyświetlajacego ˛ dane znajomego. W środkowej cześci ˛ ekranu znajduje sie˛ tabela operacji przypisanych do prezentowanego konta. Poniżej znajduje sie˛ wykres obrazujacy ˛ bilans dzienny operacji wykonanych na koncie w przeciagu ˛ ostatniego miesiaca. ˛ 5.5. Ekran operacji pomiedzy ˛ użytkownikami Na rysunku 5.5 przedstawiono ekran operacji pomiedzy ˛ użytkownika realizujacy ˛ wymaganie WF 19. W górnej cześci ˛ ekranu znajduja˛ sie˛ przyciski rozpoczynajace ˛ procesy dodawania pożyczki oraz operacji w parze. Poniżej umieszczono tabele, ˛ która prezentuje dane wykonanych operacji. 5.6. Ekran kont pomiedzy ˛ użytkownikami 45 Rysunek 5.5: Ekran operacji pomiedzy ˛ użytkownikami 5.6. Ekran kont pomiedzy ˛ użytkownikami Na rysunku 5.6 zaprezentowany jest ekran kont pomiedzy ˛ użytkownikami, z aktywna˛ funkcja˛ podsumowania. W takim stanie realizuje on wymagania WF 16, WF 17 oraz WF 22. W górnej cześci ˛ ekranu znajduje sie˛ przycisk uruchamiajacy ˛ proces dodawania nowego konta użytkownika. W tabeli zaprezentowana jest lista aktywnych kont. W dolnej cz˛eści ekranu prezentowane jest podsumowanie kont w formie wykresów. Rysunek 5.6: Ekran kont pomiedzy ˛ użytkownikami 5.7. Ekran wyświetlajacy ˛ informacje o znajomym 46 5.7. Ekran wyświetlajacy ˛ informacje o znajomym Na rysunku 5.7 przedstawiono ekran informacji o znajomym. Oprócz informacji podstawowych prezentowane sa˛ informacje o kontach posiadanych z danym użytkownikiem oraz o wykonanych z nim operacjach. Ekran ten realizuje wymaganie WF 29. Rysunek 5.7: Ekran wyświetlajacy ˛ informacje o znajomym 5.8. Formularz uwierzytelniania Na rysunku 5.8 przedstawiony jest formularz uwierzytelniania. wymagania WF 4 oraz WF 5. Rysunek 5.8: Formularz uwierzytelniania Spełnia on 6. Implementacja rozszerzeń szkieletu Vaadin 6.1. Moduł bezpieczeństwa W zwiazku ˛ z wykorzystaniem Apache Shiro jako szkieletu zapewniajacego ˛ bezpieczeństwo zaszła potrzeba zintegrowania go z tworzona˛ aplikacja. ˛ Czesto ˛ stosowane oraz opisywane w poradnikach podejście opisywania uprawnień, ról oraz użytkowników w plikach konfiguracyjnych okazało sie˛ niewystarczajace ˛ w przypadku tworzonego systemu. Moduł bezpieczeństwa musi zapewniać poprawne działanie w przypadku rejestrowania nowych kont oraz zmiany kategorii użytkownika. Podje˛ to decyzje˛ o przechowywaniu danych użytkowników w bazie danych. 6.1.1. Rozwiazanie ˛ dostepne ˛ w Apache Shiro Apache Shiro dostarcza JDBCRealm, który pobiera dane wykorzystujac ˛ do tego interfejs programowania JDBC oraz zdefiniowane zapytania. Gdy użytkownik próbuje sie˛ zalogować lub uzyskać dostep ˛ do określonej cześci ˛ systemu parametry odpowiednich zapytań sa˛ wypełnianie, a tak przygotowane kwerendy wysyłane sa˛ do bazy danych. Rozwiazanie ˛ to ma jednak wady: — Korzysta ono z interfejsu JDBC, mimo że w aplikacji wykorzystywane jest JPA. — Współpracuje tylko z podstawowym modelem bezpieczeństwa, na który składaja˛ si˛e użytkownicy oraz uprawnienia. Nie ma wsparcia dla uwierzytelniania z wykorzystaniem OAuth. 6.1.2. Wymagania wobec nowego rozwiazania ˛ Nowo utworzone elementy modułu bezpieczeństwa musza˛ spełnić nastepuj ˛ ace ˛ wymagania: — zapewnienie współpracy z baza˛ danych z wykorzystaniem JPA oraz JTA, — integracja z CDI, — umożliwienie definiowania wymaganych uprawnień w prosty sposób, — sprawdzanie uprawnień powinno być wywoływane automatycznie, — umożliwienie rejestrowania oraz uwierzytelniania użytkowników z wykorzystaniem OAuth. W sieci Internet pod adresem github.com/davidsowerby/v7 dostepne ˛ jest rozwiazanie ˛ integrujace ˛ Vaadin z Shiro. Niestety oprócz zapewnienia sposobu łaczenia ˛ sesji modułu bezpieczeństwa z sesja˛ Vaadin nie spełnia ono wymagań. Skorzystanie z tego rozwiazania ˛ wiazałoby ˛ sie˛ również z koniecznościa˛ zastapienia ˛ CDI przez Guice oraz wykorzystania pozostałych komponentów tej biblioteki wpływajacych ˛ na architekture˛ aplikacji. 6.1. Moduł bezpieczeństwa 48 6.1.3. Integracja z baza˛ danych Integracja z baza˛ danych polegała na stworzeniu własnych dziedzin wykorzystujacych ˛ działanie szkieletu CDI oraz warstwy dostepu ˛ do danych JPA. Rysunek 6.1: Cze˛ ść architektury Apache Shiro odpowiedzialna za uwierzytelnianie i autoryzacje˛ użytkowników Twórcy szkieletu Apache Shiro ułatwiaja˛ konstrukcje˛ własnych dziedzin poprzez udoste˛ pnienie klasy abstrakcyjnej AuthorizingRealm. Rozszerzajac ˛ te˛ klase˛ należy zaimplementować dwie metody: — doGetAuthenticationInfo — doGetAuthorizationInfo. Po zaimplementowaniu tych metod nowo utworzona dziedzina bedzie ˛ wspierać zarówno operacje uwierzytelniania jak i autoryzacji. Uwierzytelnianie z wykorzystaniem hasła W projektowanym systemie została utworzona klasa VaadinAuthorizingRealm, której zadaniem jest pobieranie danych potrzebnych modułowi bezpieczeństwa. Rozszerza ona wspomniana˛ wyżej klase˛ AuthorizingRealm. W celu zwiekszenia ˛ wydajności dziedzina ta wykorzystuje zarzadc ˛ e˛ pamieci ˛ cache (ang. CacheManager) By zagwarantować bezpieczeństwo dopasowanie haseł odbywa sie˛ poprzez porównanie skrótów wygenerowanych z wielokrotnym wykorzystaniem SHA-256. Dodatkowym elementem zwie˛ kszajacym ˛ bezpieczeństwo jest wykorzystanie soli (ang. salt) losowo generowanych dla każdego użytkownika. 1 protected AuthenticationInfo doGetAuthenticationInfo ( f i n a l AuthenticationToken token ) throws AuthenticationException { checkArgument ( token instanceof UsernamePasswordToken ) ; 5 f i n a l UsernamePasswordToken userPassToken = ( UsernamePasswordToken ) token ; 10 i f ( userPassToken . getUsername ( ) == null ) { throw new AccountException ( " Null usernames are not allowed " ) ; } f i n a l User user = userDao . findByLogin ( userPassToken . getUsername ( ) ) ; 6.1. Moduł bezpieczeństwa 49 i f ( user == null ) { throw new AuthenticationException ( ) ; } 15 f i n a l SimpleAccount simpleAccount = new SimpleAccount ( user . getLogin ( ) , user . getPassword ( ) , ByteSource . U t i l . bytes ( user . g e t S a l t ( ) ) , REALM_NAME) ; 20 return simpleAccount ; } Wydruk 6.1: Metoda pobierajaca ˛ dane użytkownika w procesie uwierzytelniania Na wydruku 6.1 przedstawiono kod metody odpowiedzialnej za pobranie danych użytkownika potrzebnych w trakcie procesu uwierzytelniania. Istnieja˛ metody uwierzytelniania nie polegajace ˛ na sprawdzeniu loginu oraz hasła wiec ˛ pierwszym krokiem jest sprawdzenie, czy przekazane dane zawieraja˛ te informacje. Niemożliwa jest sytuacja gdy login jest nieokreślony co sprawdzane jest w nastepnym ˛ warunku. Po weryfikacji poprawności przekazanych danych nastepuje ˛ wyszukanie obiektu User w bazie danych oraz wypełnienie obiektu przechowujacego ˛ informacje o odnalezionym koncie. Obiekt ten zostaje zwrócony do funkcji wywołujacej. ˛ Na podstawie otrzymanego rezultatu funkcja wywołujaca ˛ może kontynuować procedure˛ uwierzytelniania. 1 protected AuthorizationInfo doGetAuthorizationInfo ( final PrincipalCollection principals ) { return databaseUtils . invokeReturn ( ( ) −> { f i n a l String l o g i n = ( String ) p r i n c i p a l s . getPrimaryPrincipal ( ) ; 5 f i n a l User user = userDao . findByLogin ( l o g i n ) ; f i n a l Set<String > r o l e s = new HashSet< >( user . getRoles ( ) . s i z e ( ) ) ; user . getRoles ( ) . forEach ( r o l e −> r o l e s . add ( r o l e . getRoleName ( ) ) ) ; 10 f i n a l Set<org . apache . shiro . authz . Permission > permissions = new HashSet < > ( ) ; user . getRoles ( ) . forEach ( r o l e −> { for ( f i n a l Permission permission : r o l e . getPermissions ( ) ) { permissions . add (new WildcardPermission ( permission . getPermission ( ) ) ) ; } }); 15 f i n a l SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo ( r o l e s ) ; authorizationInfo . setObjectPermissions ( permissions ) ; return authorizationInfo ; }); 20 } Wydruk 6.2: Metoda zwracajaca ˛ dane potrzebne do autoryzacji użytkownika Na wydruku 6.2 zaprezentowano metode, ˛ która odpowiada za przekazanie do modułu bezpieczeństwa ról oraz uprawnień użytkownika. Całość operacji odbywa si˛e w transakcji bazodanowej. Na poczatku ˛ nastepuje ˛ pobranie obiektu User na podstawie loginu. Wykorzystujac ˛ otrzymany obiekt ustalane sa˛ role użytkownika, a dzi˛eki nim jego uprawnienia. Tak zdobyte informacje wpisywane sa˛ w instancje 6.1. Moduł bezpieczeństwa 50 obiektu SimpleAuthorizationInfo zwracanego jako rezultat metody. Apache Shiro może wykorzystać wynik działania tej funkcji do sprawdzania uprawnień użytkownika. Komunikacja z serwisami poświadczajacymi ˛ Komunikacja z serwisami internetowymi oferujacymi ˛ usługe˛ OAuth odbywa si˛e za pomoca˛ dodatku do Vaadin o nazwie OAuth Popup Add-on. Komponent ten dostarcza API służace ˛ do otwierania okna, w którym użytkownik bedzie ˛ mógł potwierdzić swoja˛ tożsamość oraz przekazać odpowiednie uprawnienia aplikacji. Zadaniem programisty aplikacji jest zaimplementowanie interfejsu OAuthListener wymagajacego ˛ stworzenia dwóch metod: — authSuccessful - wywoływanej w przypadku pozytywnej odpowiedzi serwisu, — authDenied - wywoływanej w przypadku negatywnej odpowiedzi serwisu. W przypadku odpowiedzi pozytywnej należy, za pomoca˛ API oferowanego przez biblioteke˛ Scribe OAuth Library oraz otrzymanego tokenu dostepu, ˛ pobrać dane z serwisu. Uwierzytelnianie z wykorzystaniem serwisów poświadczajacych ˛ Oprócz VaadinAuthorizingRealm stworzono też dziedzine˛ OAuthAuthorizingRealm, która wykorzystuje dane otrzymane dzieki ˛ protokołowi OAuth do uwierzytelnienia użytkownika. Podobnie jak druga ze stworzonych dziedzin OAuthAuthorizingRealm dziedziczy ona po klasie AuthorizingRealm. Jednym z pierwszych kroków tworzenia dziedziny było wyłaczenie ˛ dopasowywania hasła. Zostało to zrobione poprzez stworzenie własnej implementacji CredentialsMatcher i ustawienie jej jako domyślnej dla OAuthAuthorizingRealm. Realizacja ta zwraca pozytywny wynik dopasowania dla każdego tokenu. Sposób realizacji tego zadania przedstawiony jest na wydruku 6.3. 1 5 10 @Override public CredentialsMatcher getCredentialsMatcher ( ) { return new CredentialsMatcher ( ) { @Override public boolean doCredentialsMatch ( f i n a l AuthenticationToken token , f i n a l AuthenticationInfo i n f o ) { return true ; } }; } Wydruk 6.3: Implementacja klasy dopasowujacej ˛ dane uwierzytelniajace ˛ Naste˛ pnym krokiem było stworzenie klasy tokena, który bedzie ˛ wymagany przez nowa˛ dziedzine˛ . Proponowana klasa OAuthAuthenticatingToken zawiera dwie składowe: — service - be˛ dac ˛ a˛ tekstowa reprezentacja˛ serwisu, z którego pobierane sa˛ dane, — id - be˛ dacy ˛ identyfikatorem użytkownika we wspomnianym serwisie. Tak przygotowany token przetwarzany jest przez metode˛ doGetAuthenticationInfo klasy OAuthAuthorizingRealm. Jej implementacja przedstawiona jest na wydruku 6.4. 1 @Override protected AuthenticationInfo doGetAuthenticationInfo ( 6.1. Moduł bezpieczeństwa 51 f i n a l AuthenticationToken token ) throws AuthenticationException { checkArgument ( token instanceof OAuthAuthenticatingToken ) ; 5 f i n a l OAuthAuthenticatingToken oAuthAuthenticatingToken = ( OAuthAuthenticatingToken ) token ; checkNotNull ( oAuthAuthenticatingToken . getService ( ) ) ; checkNotNull ( oAuthAuthenticatingToken . getId ( ) ) ; 10 OAuthAccount oAuthAccount = oAuthAccountDao . findBySerivceAndServiceId ( oAuthAuthenticatingToken . getService ( ) , oAuthAuthenticatingToken . getId ( ) ) ; 15 i f ( oAuthAccount == null ) { throw new AuthenticationException ( ) ; } 20 User user = oAuthAccount . getUser ( ) ; f i n a l SimpleAccount simpleAccount = new SimpleAccount ( user . getLogin ( ) , user . getPassword ( ) , ByteSource . U t i l . bytes ( user . g e t S a l t ( ) ) , REALM_NAME) ; 25 return simpleAccount ; } Wydruk 6.4: Pobieranie danych uwierzytelniajacych ˛ w klasie OAuthAuthorizingRealm Pierwszym krokiem, po sprawdzeniu poprawności przekazanych parametrów, jest pobranie konta OAuth zarejestrowanego w systemie dla danego serwisu i identyfikatora użytkownika. Jeśli takie konto nie istnieje zwracany jest bład ˛ uwierzytelniania. W przeciwnym przypadku pobierana jest instancja klasy User reprezentujaca ˛ użytkownika, z którym połaczone ˛ jest konto OAuth. Na podstawie tego konta budowany jest obiekt SimpleAccount wykorzystywany przez Apache Shiro do przetrzymywania danych użytkownika. Niezależnie od hasła zostanie on zaakceptowany przez zdefiniowana˛ na wydruku 6.3 klase. ˛ Podejście takie jest bezpieczne ponieważ instancje klasy OAuthAuthenticatingToken tworzone sa˛ wyłacznie ˛ po stronie serwera aplikacyjnego w sytuacji pozytywnej odpowiedzi serwisu poświadczajacego. ˛ 6.1.4. Rodzaje uprawnień Apache Shiro dostarcza adnotacje które określaja˛ jakie wymagania musi spełnić użytkownik by moduł bezpieczeństwa zezwolił na wywołanie funkcji. Ich lista przedstawiona jest poniżej. — RequiresUser - Użytkownik musi być uwierzytelniony. — RequiresAuthentication - Użytkownik musi być uwierzytelniony lecz nie jest akceptowane uwierzytelnienie poprzez skorzystanie z opcji "Pamietaj ˛ mnie". — RequiresGuest - Użytkownik nie może być uwierzytelniony. — RequiresPermissions - Użytkownik musi posiadać uprawnienia bed ˛ ace ˛ argumentami adnotacji. — RequiresRoles - Użytkownik musi posiadać role bed ˛ ace ˛ argumentami adnotacji. 6.1. Moduł bezpieczeństwa 52 6.1.5. Sprawdzanie uprawnień W celu integracji modułu bezpieczeństwa z tworzonym systemem należało zaimplementować funkcje˛ sprawdzania adnotacji Apache Shiro w sposób niewymagajacy ˛ każdorazowego wywoływania metod weryfikujacych. ˛ Tak zaprogramowany komponent gwarantuje niemożliwość jego pominiecia ˛ podczas wywołania metody oraz znaczaco ˛ ułatwia tworzenie aplikacji. W zwiazku ˛ z powyższymi wymaganiami zdecydowano sie˛ na wykorzystanie możliwości przechwytywania wywołań metod obiektów utworzonych z wykorzystaniem CDI. W tym celu wykorzystano rozwiaza˛ nie zaproponowane przez Bauke Scholtz [1]. Pierwszy krokiem było utworzenie adnotacji ShiroSecured służacej ˛ do oznaczania metod oraz klas, które powinny podlegać przechwytywaniu. Nastepnie ˛ należało utworzyć klase˛ zawierajac ˛ a˛ metode˛ obsługi punktu przeciecia. ˛ W stworzonej aplikacji odpowiada za to klasa ShiroSecuredInterceptor. Na wydruku 6.5 przedstawiono najważniejsze elementy jej budowy. Adnotacja Interceptor sprawia, że przy uruchomieniu aplikacji CDI automatycznie zarejestruje˛ te˛ klase˛ jako przechwytywacz dla metod oznaczonych adnotacjami ShiroSecured. W momencie wywołania chronionych metod zostanie najpierw wykonana treść metody interceptShiroSecurity. Dzieje sie˛ tak dzie˛ ki obecności adnotacji AroundInvoke. Kod wspomnianej funkcji został pominie˛ ty w celu zwiekszenia ˛ czytelności wydruku. 1 package pl . dziurdziak . easyReckoning . u t i l s . security . permissionChecker ; import javax . i n t e r c e p t o r . ∗ ; import org . apache . shiro . subject . Subject ; 5 @Interceptor @ShiroSecured public class ShiroSecuredInterceptor { @Inject private Subject subject ; 10 @AroundInvoke public Object interceptShiroSecurity ( f i n a l InvocationContext context ) throws Exception { //code omitted } 15 } Wydruk 6.5: Najważniejsze elementy budowy klasy ShiroSecuredInterceptor W wyniku tych działań możliwe stało sie˛ deklaratywne opisywanie zabezpieczeń metod. Na wydruku 6.6 przedstawiono sposób zabezpieczenia metody, który zezwoli na jej wywołanie tylko uwierzytelnionemu użytkownikowi. 1 @ShiroSecured @RequiresUser public void viewEntered ( ) { } Wydruk 6.6: Przykład metody zabezpieczonej za pomoca˛ adnotacji 6.2. MVP oraz nawigacja 53 6.2. MVP oraz nawigacja Vaadin jako zaawansowany szkielet aplikacyjny dostarcza szeregu komponentów i modułów wykorzystywanych podczas tworzenia systemu. Wśród nich znajduje sie˛ moduł nawigacji wykorzystujacy ˛ analize˛ adresu url. Niestety domyślne rozwiazanie ˛ nie spełniało stawianych przed nim wymagań w zwiazku ˛ z czym podj˛eto decyzje˛ o stworzeniu własnego rozszerzenia odpowiedzialnego za nawigacje. ˛ 6.2.1. Sposób nawigacji w Vaadin Podstawowym sposobem nawigacji w aplikacji napisanej w szkielecie Vaadin jest skorzystanie z klasy Navigator. Przykład wykorzystania takiego sposobu przedstawiony jest na wydruku 6.7. 1 public class NavigationTestUI extends UI { @Override public void i n i t ( VaadinRequest request ) { Navigator navigator = new Navigator ( this , this ) ; navigator . addView ( "main" , new MainView ( ) ) ; navigator . addView ( " count " , CountView . class ) ; } 5 10 } Wydruk 6.7: Wykorzystanie nawigacji za pomoca˛ klasy Navigator W pierwszej linii metody init rejestrowany jest nowy Navigator, który bedzie ˛ odpowiadał za zmiany zawartości głównego okna aplikacji. Navigator śledzi zmiany adresu w pasku przegladarki ˛ i na jego podstawie ustala jaki widok ma zostać wyświetlony. Decyzja o widoku, który ma zostać wyświetlony podejmowana jest dzi˛eki jego nazwie podawanej w metodzie addView. W prezentowanym przykładzie adres postaci 1 www. example .com/#main sprawi, że zostanie wyświetlony widok MainView. Domyślnie Navigator ustala jakie instancje widoku maja˛ zostać wyświetlone w dwojaki sposób. Jeśli do metody addView zostanie przekazany obiekt oznacza to, że ten obiekt zostanie wyświetlony. Gdy do tej funkcji zostanie przekazana klasa widoku Navigator zainicjalizuje jej instancje˛ za pomoca˛ domyślnego konstruktora i dopiero tak otrzymany obiekt wyświetli. Wszystkie znaki znajdujace ˛ sie˛ w adresie strony po nazwie widoku oraz znaku traktowane sa˛ jako parametry. Na poniższym przykładzie do widoku MainView parametrem be˛ dzie ciag ˛ znaków parameters/second/first. 1 www. example .com/#main/parameters/second/ f i r s t 6.2.2. Wady nawigacji w Vaadin Podstawowy sposób nawigacji w aplikacji stworzonej za pomoca˛ Vaadina nie ustrzegł sie˛ wad. Do mankamentów tej metody można zaliczyć: 6.2. MVP oraz nawigacja 54 — Brak zaawansowanego wsparcia dla przekazywania parametrów do widoków. Otrzymany łańcuch tekstowy, który jest parametrem musi zostać zanalizowany i przetworzony przez kod klasy widoku. — Brak wsparcia dla automatycznej budowy hierarchii widoków zagnieżdżonych wewnatrz ˛ innych. — Wykorzystywanie przekazanych instancji obiektów lub ich inicjalizacja za pomoca˛ domyślnego konstruktora. Jest to duża wada w środowisku działajacym ˛ w oparciu o szkielet wspierajacy ˛ wstrzykiwanie zależności. Nowo powstałe widoki pozbawione sa˛ referencji do obiektów zazwyczaj wstrzykiwanych przed odpowiedni komponent. — W przypadku zastosowania wzorca MVP konieczne jest powiazanie ˛ otrzymanego widoku z prezenterem. 6.2.3. Wymagania wobec nowego rozwiazania ˛ Nowo powstały mechanizm nawigacji powinien być pozbawiony wad nawigatora domyślnego. Stawiane przed nim wymagania to: — wsparcie dla widoków zagnieżdżonych, — możliwość przekazywania parametrów dla widoków na dowolnym poziomie zagnieżdżenia, — korzystanie z dobrodziejstw wstrzykiwania zależności, — obsługa wzorca MVP, — wysoki poziom automatyzacji. 6.2.4. Wykorzystane rozwiazanie ˛ Architektura MVP Na rysunku 6.2 przedstawiono klasy i interfejsy należace ˛ do wykorzystanego modelu MVP. Każdy widok aplikacji musi implementować interfejs MvpView, który wymaga stworzenia dwóch metod: — enter - wywoływanej w momencie otwarcia widoku, — getComponent - służacej ˛ do pobrania treści widoku w celu jej wyświetlenia. Widoki przyjmujace ˛ parametry musza˛ implementować interfejs ParametrizedView. Interfejs ten nie wymaga od klas posiadania żadnych metod ponieważ różne widoki moga˛ oczekiwać różnej liczby oraz innego rodzaju argumentów. Sposób przekazywania parametrów zostanie omówiony w dalszej cześci ˛ tego rozdziału. Klasy widoku, które moga˛ zawierać widoki zagnieżdżone musza˛ implementować interfejs NavigatableView. Jego dwie metody służa˛ do ustawiania (setMvpView) oraz pobierania (getMvpView) aktualnego widoku zagnieżdżonego. Interfejsy widoków posiadaja˛ odpowiadajace ˛ im interfejsy prezenterów. Podstawowa˛ klasa˛ hierarchii prezenterów jest MvpPresenter, zawierajacy ˛ deklaracje wyłacznie ˛ jednej metody, która zostanie wywołana w momencie otwarcia widoku. Pozostałe elementy struktury dziedziczenia służa˛ do zapewnienia, że do widoków odpowiednich typów zostana˛ przekazane właściwe prezentery. Interfejs NavigatableUI powinna implementować główna klasa aplikacji. Zapewnia on, że możliwe be˛ dzie ustawianie widoków. Oprócz wymienionych powyżej interfejsów nowy szkielet nawigacji dostarcza dwie klasy abstrakcyjne warstwy widoku. W konstruktorach tych klas pobierane sa˛ właściwe instancje prezenterów dzieki ˛ czemu programista ma zapewniony dostep ˛ 6.2. MVP oraz nawigacja 55 Rysunek 6.2: Zastosowana architektura wzorca MVP do tych obiektów. AbstractNavigatableView zapewnia również obsługe˛ ustawiania i pobierania widoków zagnieżdżonych. Konfiguracja Każdy widok musi posiadać odpowiadajaca ˛ mu klase˛ prezentera, który odpowiada za nadzorowanie jego zachowania oraz obsługe˛ przychodzacych ˛ zdarzeń. Dzi˛eki temu, że klasy AbstractMvpView oraz AbstractNavigatableView sa˛ typami generycznymi warunek ten jest zawsze spełniony. 6.2. MVP oraz nawigacja 56 Oprócz powiazania ˛ z prezenterem każdy widok musi zostać oznaczony adnotacja˛ @ViewName przechowujac ˛ a˛ informacje˛ o nazwie widoku. Nazwa widoku musi być unikalna. Obecnie dla poprawnego działania modułu nawigacji widoki musza˛ być powia˛ zane z zakresem interfejsu graficznego użytkownika. Osiaga ˛ sie˛ to poprzez stosowanie adnotacji UIScoped. Ze wzgle˛ dów bezpieczeństwa widoki, w których moga˛ być zagnieżdżane inne musza˛ być oznaczone niepusta adnotacja˛ @NavigateTo. Adnotacja ta przechowuje informacje o klasach widoków, których obiekty moga˛ być prezentowane wewnatrz ˛ widoku nadrze˛ dnego. 1 5 @ViewName( " userAccounts " ) @NavigateTo ( { UserAccountDetailsView . class , UserAccountsSummaryView . class } ) @UIScoped public class UserAccountsView extends AbstractNavigatableView <UserAccountsPresenter > { Wydruk 6.8: Konfiguracja widoku UserAccountsView Widoki przyjmujace ˛ argumenty musza˛ posiadać metode˛ oznaczona˛ adnotacja˛ @ParamMethod, która sprawi, że podczas pracy modułu nawigacji parametry odczytane z adresu url zostana˛ przekazane przed wywołaniem funkcji enter. Metoda ta musi przyjmować co najmniej jeden parametr. Wszystkie argumenty funkcji powinny zostać oznaczone adnotacjami @Param, dzieki ˛ którym możliwe bedzie ˛ dopasowanie nazw parametrów odczytanych z adresu url z zadeklarowanymi argumentami metody. 1 @ParamMethod public void setParams (@Param( " tabId " ) f i n a l Integer tabId ) { presenter . setParams ( tabId ) ; } Wydruk 6.9: Przykład metody przyjmujacej ˛ parametry Mimo, że parametry odczytywane z adresu url sa˛ łańcuchami znaków istnieje możliwość deklarowania parametrów dowolnego typu w metodzie oznaczonej adnotacja˛ @ParamMethod. Moduł nawigacji wspiera przekazywanie argumentów typu Integer oraz Long. Jeśli programista pragnie odczytywać parametry innych typów musi zaimplementować interfejs Deserializer<T> oraz zarejestrować implementacje˛ klasy w module nawigacji. 1 public interface D e s e r i a l i z e r <T> { T d e s e r i a l i z e r ( String s e r i a l i z e d ) throws DeserializationException ; Class <? extends T> getDeserializedClass ( ) ; 5 } Wydruk 6.10: Interfejs Deserializer<T> 57 6.2. MVP oraz nawigacja Uruchomienie aplikacji Moduł nawigacji korzysta z możliwości udostepnianych ˛ przez CDI. Do jednej z nich należy stworzenie własnego rozszerzenia, które może nasłuchiwać zdarzeń zwiazanych ˛ z procesem odkrywania klas, który zachodzi podczas startu aplikacji. Naste˛ pujace ˛ operacje wykonywane sa˛ podczas uruchamiania aplikacji: — Sprawdzenie czy każda klasa implementujaca ˛ interfejs MvpView oznaczona jest adnotacja˛ @ViewName. — Analiza czy wszystkie widoki posiadaja˛ unikalne nazwy. — Sprawdzenie czy każdy widok implementujacy ˛ interfejs NavigatableView posiada niepusta adnotacje˛ @NavigateTo. — Sprawdzenie czy każdy widok implementujacy ˛ interfejs ParametrizedView posiada metode˛ oznaczona˛ adnotacja˛ @ParamMethod oraz czy wszystkie parametry tej metody oznaczone sa˛ za pomoca˛ @Param. — Budowana jest dwukierunkowa mapa odwzorowujaca ˛ nazwy widoków na ich klasy. Przetrzymywana jest ona w obiekcie ViewResolver. Niespełnienie któregokolwiek z powyższych warunków skutkuje zgłoszeniem błedu, ˛ który uniemożliwia start aplikacji. Proces nawigacji Moduł nawigacji reaguje na zmiany adresu url. Pierwszym krokiem jest podział adresu według schematu przedstawionego na rysunku 6.3. W wyniku tego podziału zwracana jest lista obiektów przetrzymujacych ˛ nazwy kolejnych widoków wraz z ich parametrami. Na szczególna˛ uwage˛ zasługuje tutaj znak "#", którego obecność sprawia, że modyfikacje cze˛ ści adresu url za nim nie skutkuja˛ przeładowaniem strony. Rysunek 6.3: Podział adresu url Lista otrzymana w poprzednim kroku poddawana jest dalszemu przetwarzaniu. Proces ten został zobrazowany na rysunku 6.4. Moduł nawigacji zwróci bład ˛ w przypadku gdy nazwy lub krotność parametrów odczytanych z adresu url nie bed ˛ a˛ zgodne z argumentami oczekiwanymi przez metode˛ widoku. 6.2. MVP oraz nawigacja Rysunek 6.4: Przebieg procesu nawigacji 58 7. Podsumowanie Celem niniejszej pracy inżynierskiej było zaprojektowanie i zaimplementowanie aplikacji internetowej wspierajacej ˛ proces wspólnego rozliczania wydatków. Wszystkie wymagania przedstawione w rozdziale drugim zostały spełnione przez stworzone oprogramowanie. Pobocznym zadaniem, które należało wykonać podczas implementacji systemu było zintegrowanie bibliotek i szkieletów programistycznych wykorzystanych podczas pracy implementacyjnej. Ze wzgle˛ du na ograniczenia czasowe poświecono ˛ niedostateczna˛ uwage˛ dopracowaniu wygladu ˛ graficznego interfejsu użytkownika. Nie wpłyneło ˛ to na możliwości powstałej aplikacji. W trakcie tworzenia aplikacji autor niniejszej pracy zapoznał sie˛ z nieznanymi sobie do tej pory bibliotekami, szkieletami aplikacyjnymi, wzorcami projektowymi. Implementacja wymogła na nim zaznajomienie sie˛ ze sposobami administrowania serwerami aplikacyjnymi oraz baza˛ danych. Zaowocowało to zdobyciem cennej wiedzy na temat programowania, możliwości jezyka ˛ Java oraz zarzadzania ˛ projektem. Otwartych pozostaje wiele ścieżek rozwoju aplikacji. Dalsze prace moga˛ uwzgle˛ dniać zmodernizowanie interfejsu graficznego oraz implementacje˛ dodatkowych funkcji systemu. Interesujacym ˛ zagadnieniem może również być stworzenie aplikacji na platformy mobilne współpracujacej ˛ ze specjalnie w tym celu zmodernizowanym systemem. Bibliografia [1] Analiza Apache Sshiro w środowisku Java EE 6. balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html. [Online; dostep ˛ 22 sierpnia 2014]. [2] DB-Engines ranking. db-engines.com/en/ranking. [Online; dostep ˛ 3 sierpnia 2014]. [3] Funkcjonalności postgreSQL. www.postgresql.org/about/featurematrix/. [Online; dostep ˛ 24 sierpnia 2014]. [4] Google trends - popularność frazy Vaadin. www.google.pl/trends/explore?q=vaadin. [Online; dostep ˛ 15 lipca 2014]. [5] Google trends - popularość frazy AngularJS. www.google.pl/trends/explore?q=AngularJS. [Online; dostep ˛ 25 sierpnia 2014]. [6] Opis Oracle Database Express Edition 11g. www.oracle.com/technetwork /database/database-technologies/express-edition/overview/index.html. [Online; dostep ˛ 24 sierpnia 2014]. [7] Popularność serwerów aplikacyjnych. http://www.javacodegeeks.com/2013/03 /most-popular-application-servers.html. [Online; dostep ˛ 25 sierpnia 2014]. [8] Porównanie popularności systemów operacyjnych. www.netmarketshare.com. [Online; dostep ˛ 24 sierpnia 2014]. [9] Porównanie wersji Oracle Database. www.oracle.com/us/products/database /enterprise-edition/comparisons/index.html. [Online; dostep ˛ 24 sierpnia 2014]. [10] Porównanie wersji SQL Server 2014. msdn.microsoft.com/en-us/library /cc645993.aspx. [Online; dostep ˛ 24 sierpnia 2014]. [11] Standardy sql w postgreSQL. www.postgresql.org/docs/current/static/features.html. [Online; dostep ˛ 24 sierpnia 2014]. [12] Vaadin directory. vaadin.com/directory. [Online; dostep ˛ 15 lipca 2014]. [13] Christian Bauer, Gavin King. Java Persistence with Hibernate. Manning Publications Co., Greenwich, 2007. [14] Sami Ekblad. Vaadin directory celebrates 3 years. vaadin.com/blog/-/blogs/vaadin-directory-celebrates-3-years. [Online; dostep ˛ 10 lipca 2014]. [15] Antonio Goncalves. Beginning Java EE 6 Platform with GlassFish 3. Apress, 2010. [16] Les Hazlewood. Application Security With Apache Shiro. www.infoq.com/articles/apache-shiro. [Online; dostep ˛ 20 lipca 2014]. [17] Bartek Kuczyński. Vaadin 7 - naprawde˛ szybkie tworzenie aplikacji web w javie. Programista, listopad 2013. [18] Krzysztof Sacha. Inżynieria oprogramowania. Wydawnictwo Naukowe PWN SA, Warszawa, 2010. [19] Mark Seemann. Dependency Injection in .NET, strony 155–156. Manning Publications Co., Shelter Island, 2012.