redseeds podręcznik użytkownika -...
TRANSCRIPT
ReDSeeDS
Podręcznik Użytkownika
Redakcja: Michał Śmiałek
Politechnika Warszawska
ReDSeeDS
Podręcznik Użytkownika(dla wersji 0.6.5 i 0.7.0)
Michał Bujnowski Redakcja: Michał Śmiałek
smog.iem.pw.edu.pl
Podręcznik Użytkownika
smog.iem.pw.edu.pl
1
Podręcznik jest opracowany na podstawie pracy inżynierskiej wykonanej w IETiSIP
Politechniki Warszawskiej.
2
1. Modelowanie wymagań w narzędziu ReDSeeDS
1.1. Przypadki użycia
1.1.1. Tworzenie przypadków użycia w narzędziu ReDSeeDS
Na początku, jeżeli jeszcze nie mamy, musimy stworzyć katalog z wymaganiami. W tym celu
rozwijamy drzewo projektu, klikamy prawym przyciskiem myszy na katalog Requirements
Specification -> New -> Requirements Package, następnie podajemy nazwę i wciskamy
Finish. W efekcie utworzył nam się specjalny katalog o podanej nazwie.
W utworzonym katalogu należy umieszczać diagramy przypadków użycia. Aby stworzyć
diagram należy przycisnąć prawym przyciskiem myszy na utworzonym katalogu, następnie
New -> Use Cases Diagram, następnie podać nazwę dla diagramu i wcisnąć Ok. Utworzy się
diagram oraz automatycznie otworzy jego podgląd.
Każdy diagram przypadków użycia musi zawierać aktora. By go dodać należy w widoku
diagramu wybrać z Pallete -> Elements -> Actor i następnie kliknąć na diagramie bądź
kliknąć prawym przyciskiem myszy na diagramie, następnie wybrać Add -> Actor.
Tworzyć przypadki użycia można na trzy sposoby – dwa zostały omówione przed chwilą, z tą
rożnicą, że zamiast Actor wybieramy Use Case. Trzeci sposób polega natomiast na
przyciśnięciu prawym przyciskiem myszy na katalogu projektu New -> Use Case wpisaniu
nazwy, następnie potwierdzeniu poprzez wciśnięcie Ok. Taki przypadek użycia musimy
jeszcze przeciągnąć do diagramu.
Przypadek użycia może być wywoływany bezpośrednio przez aktora, aby zamodelować taką
sytuację należy wybrać z Pallete -> Connections -> Assocation kliknąć na aktora, a następnie
na przypadek użycia lub najechać kursorem na aktora i wybrać strzałkę skierowaną na
kwadrat i przeciągnąć ją na przypadek użycia. Tworzenie bezpośredniej relacji przypadków
użycia opiszę w rozdziale 2.2.1, który dotyczy tworzenia scenariuszy przypadków użycia.
1.1.2. Modele przypadków użycia dla systemu rezerwacji zasobów
Stosując się do powyższej instrukcji stworzyłem katalog Use Cases w którym są 4
podkatalogi. Ich podział wynikł naturalnie z zakresu funkcjonalnego systemu: zarządzanie
pracownikami, zarządzanie zasobami, rezerwacje oraz logowanie. Na rysunku 2.1
przedstawiona jest struktura katalogów.
3
Rys. 2.1 Struktura przypadków użycia
Logowanie
Pierwszym diagramem jaki stworzyłem zawierał przypadki użycia logowania użytkowników.
Zidentyfikowałem dwie role – manager oraz pracownik. Manager będzie miał dostęp do
wszystkich opcji systemu natomiast pracownik będzie mógł tylko dokonywać rezerwacji.
Aktorzy są w bezpośredniej relacji tylko z jednym przypadkiem użycia, z racji na fakt, że
tylko zautoryzowany użytkownik może korzystać z funkcjonalności systemu. Na kolejnych
diagramach będą wykorzystane przypadki użycia logowania, by pokazać tą cechę systemu.
Już na etapie tworzenia aktorów natknąłem się na ograniczenie narzędzia ReDSeeDS, gdyż
chciałem zamodelować jeden przypadek użycia dla obydwu ról. Niestety w narzędziu
ReDSeeDS w diagramach przypadków użycia nie można stosować dziedziczenia, stąd podział
wymagań nastąpił na logowanie jako manager oraz logowanie jako pracownik. Rysunek 2.2
pokazuje diagram logowania.
4
Rys. 2.2 Diagram przypadków użycia katalogu SignIn
Zarządzanie pracownikami
Diagram przedstawiający przypadki użycia do zarządzania pracownikami znajduje się na
rysunku 2.3. Aktor manager ma bezpośredni dostęp tylko do jednego przypadku użycia –
logowania. Mimo, że jest ono zamodelowane już na innym diagramie, to ma ono sens, gdyż
manager dopiero po pomyślnym logowaniu ma dostęp do wyświetlenia listy pracowników. Z
poziomu listy pracowników aktor ma możliwość dodania nowego użytkownika, usunięcia
istniejącego, wyświetlenia informacji szczegółowych o pracowniku oraz edycję tych
informacji. Dodatkowo z poziomu informacji szczegółowych o pracowniku, może on
zmodyfikować dane bądź je usunąć.
Jak można zauważyć, są to typowe operacje CRUD (Create, Read, Update, Delete), jednakże
nie ma potrzeby zwiększenia ilości przypadków użycia, ponieważ są one wystarczające by
zapewnić dostateczną kontrolę nad pracownikami.
Kluczowe przy dodawaniu pracownika jest nadanie mu loginu, hasła i przypięcie do
lokalizacji. Danymi logowania pracownik będzie mógł posłużyć się przy logowaniu do
systemu, natomiast lokalizacja ma wpływ na możliwości w rezerwacjach – gdyż użytkownik
ma dostęp tylko i wyłącznie do zasobów z jego lokalizacji.
Rys. 2.3 Diagram przypadków użycia katalogu EmployeeAdministration
5
Zarządzanie zasobami
Diagram przedstawiający przypadki użycia do zarządzania zasobami z punktu widzenia
operacji niczym nie różni się od zarządzania pracownikami. Również występują tu typowe
operacje CRUD (Create, Read, Update, Delete). Manager ma dostęp do listy zasobów dopiero
po autoryzacji. Następnie z listy zasobów może dodać, zmodyfikować, wyświetlić i usunąć
zasób. Po wyświetleniu informacji szczegółowych o zasobie jest w stanie wywołać przypadek
użycia edycji lub usunięcia zasobu, którego detale wyświetla. Rysunek 2.4 przedstawia
diagram zarządzania zasobami.
Przy dodawaniu zasobów, manager ma możliwość wyboru lokalizacji w jakiej zasób ma być
dostępny – ograniczenie jest po to, by pracownicy nie mogli rezerwować zasobów, do których
nie mają fizycznej możliwości dostępu.
Rys. 2.4 Diagram przypadków użycia katalogu ResourceAdministration
Rezerwacje zasobów
Diagram z przypadkami użycia do rezerwacji zasobów znajduje się na rysunku 2.5. Można na
nim zaobserwować, że pracownik ma dostęp do listy rezerwacji dopiero po poprawnej
autoryzacji. Z listy z kolei ma dostęp do wszystkich operacji na rezerwacji – dodawanie,
wyświetlanie, edycję jak również potwierdzanie i anulowanie rezerwacji. Dodatkowo z
poziomu szczegółów rezerwacji, ma on możliwość potwierdzenia jej, anulowania bądź edycji.
Pracownik dodając wydarzenie ma możliwość wyboru zasobów tylko i wyłącznie z
lokalizacji, do której jest przypisany.
6
Rys. 2.5 Diagram przypadków użycia katalogu ResourceBooking
1.2. Scenariusze przypadków użycia w narzędziu ReDSeeDS
1.2.1. Tworzenie scenariuszy w narzędziu ReDSeeDS
Mając przypadek użycia możemy przejść do tworzenia scenariuszy. Scenariusz opisuje
interakcję aktora z systemem, gdzie celem jest wykonanie przypadku użycia. Aby przejść do
okna scenariusza, należy dwukrotnie kliknąć na przypadku użycia – albo w drzewie projektu,
albo na diagramie, a następnie przejść na drugą zakładkę, która nazywa się tak jak scenariusz.
Jeżeli nazwa nie była edytowana, to scenariusz nazywa się tak jak przypadek użycia.
Pole precondition można uzupełnić warunkami początkowymi, jednak nie jest to wymagane
do wygenerowania kodu. Następnie z górnego menu wybieramy Create SVO sentence
(kolorowy przycisk SVO) i możemy przystąpić do tworzenia pierwszego zdania w
scenariuszu.
Aby stworzyć scenariusz alternatywny, należy kursorem ustawić się na odpowiednim zdaniu
scenariusza i wybrać z górnego menu Fork scenario. W efekcie doda się warunek w
scenariuszu głównym oraz stworzy się scenariusz alternatywny. Jeżeli okaże się jednak, że
alternatywny scenariusz jest zbędny i chcemy go usunąć, to musimy wykonać dwie czynności.
Przejść do scenariusza alternatywnego i wcisnąć przycisk Delete scenario, a następnie w
scenariuszu głównym ustawić kursor na warunku i użyć przycisku Delete sentence.
Scenariusz główny musi się zakończyć sukcesem lub porażką, w tym celu z górnego menu
wybieramy odpowiednio Create final/success sentence lub Create final/failure sentence,
natomiast scenariusze alternatywne mogą być zakończone poprzez użycie ww. opcji bądź
poprzez połączenie ze scenariuszem głównym. W tym celu wybieramy z górnego menu
7
Create rejoin sentence, następnie wybieramy scenariusz i zdanie scenariusza, które ma zostać
wykonane po przejściu scenariusza alternatywnego.
Kolejnym krokiem jest określenie członów zdań i przypisanie im znaczeń. W tym celu należy
zaznaczyć poszczególne części zdania, kliknąć prawym przyciskiem myszy i wybrać część
mowy. W efekcie zmieni się kolor tekstu – jest to znak rozpoznawczy czy wykonana została
powyższa czynność. Aby przypisać znaczenie do pojęcia, należy dwukrotnie kliknąć na części
zdania i wybrać przycisk Add all. Narzędzie ReDSeeDS w wersji 0.6.5. domyślnie ustawia
znaczenie Auto generated sense for word: x, które użytkownik może zmienić. Najprostszym
sposobem na zmianę jest skorzystanie z Domain Managera – przycisk z literą D w górnym
menu.
Stworzone w ten sposób pojęcia znajdują się w katalogu Domain Specification/Notions.
Należy ustawić im prawidłowy typ oraz w zależności od niego uzupełnić opis. Zasady
używania znajdują się w tabeli 2.1.
Po zmianie typu należy wrócić do scenariusza i ustawić prawidłowe Sentence Type oraz
Action Type. W większości przypadków narzędzie ReDSeeDS potrafi samo poprawnie
uzupełnić te pola na bazie orzeczenia i typu pojęcia, natomiast należy to zweryfikować, gdyż
pojawiają się błędy.
Typ Znaczenie Opis
Concept Pojęcie biznesowe Pozostaje pusty
Screen Okno <fr>
Message Komunikat <ms>Treść komunikatu</ms>
Trigger Przycisk <tr>
Attribute Atrybut <at>
ListView Widok listy <li>
SimpleView Widok formularza Pozostaje pusty
Tab. 2.1 Tabela zawierająca znaczenie i sposób zastosowania typów pojęć
1.2.2. Scenariusze dla systemu rezerwacji zasobów
W tym rozdziale opiszę najbardziej reprezentatywne scenariusze. Z racji na fakt, że przypadki
użycia zarządzania zasobami i pracownikami, praktycznie są identyczne, wybiorę po kilka
przypadków z każdego pakietu.
Logowanie
Na rysunku 2.6 znajduje się scenariusz główny logowania, który polega na autoryzacji
managera. Scenariusz logowania pracownika jest identyczny pod względem sekwencji
kroków, jednakże różni się aktorem, który wchodzi w interakcję z systemem. Po pozytywnie
zakończonej autoryzacji wyświetla się ekran główny managera, z którego można wywołać
przypadek wyświetlenie listy zasobów oraz wyświetlenia listy pracowników.
8
Rys. 2.6 Scenariusz główny przypadku użycia logowania managera
W przypadku błędnych danych logowania przewidziany jest scenariusz alternatywny, który
po nieprawidłowym wyniku autoryzacji wyświetli komunikat błędu. Na rysunku 2.7
przedstawiony jest scenariusz alternatywny.
Rys. 2.7 Scenariusz alternatywny przypadku użycia logowania managera
Wyświetlanie listy pracowników
Rysunek 2.8 przedstawia interakcję użytkownika z systemem w celu wyświetlenia listy
pracowników. Manager wciska przycisk wyświetlenie listy pracowników, następnie system
pobiera dane oraz je wyświetla. Z przypadku użycia wyświetlania listy pracowników,
manager jest w stanie stworzyć nowego pracownika lub wyświetlić, zmodyfikować i usunąć
dane już istniejącego użytkownika.
Rys. 2.8 Scenariusz przypadku użycia wyświetlania listy pracowników
9
Dodawanie pracownika
Manager może stworzyć nowego pracownika, poprzez wybór przycisku dodania pracownika.
W efekcie wyświetla się formularz, który uzupełniany jest danymi pracownika. Po
uzupełnieniu danych manager zatwierdza wprowadzone dane, następnie system je weryfikuje.
Jeżeli weryfikacja przebiegła pomyślnie, system tworzy użytkownika o podanych danych i
wyświetla komunikat sukcesu, w przeciwnym wypadku uruchamiany jest scenariusz
alternatywny i system wyświetla komunikat błędnych danych. Scenariusz ten łączy się ze
scenariuszem głównym na wyświetleniu formularza, dlatego manager może poprawić dane i
spróbować ponownie stworzyć użytkownika. Rysunek 2.9 przedstawia scenariusz główny,
natomiast na rysunku 2.10 znajduje się scenariusz alternatywny.
Rys. 2.9 Scenariusz główny przypadku użycia dodawania pracownika
Rys. 2.10 Scenariusz alternatywny przypadku użycia dodawania pracownika
Wyświetlanie informacji szczegółowych zasobu
Rysunek 2.11 przedstawia scenariusz przypadku użycia wyświetlania szczegółów
dotyczących zasobu. W tym celu manager klika na przycisku wyświetlania zasobów, w
odpowiedzi system pobiera dane zasobu i wyświetla je w specjalnym oknie. Ten przypadek
użycia jest w bezpośredniej relacji z innymi przypadkami użycia, o czym świadczą zdania
invoke/INSERT.
Rys. 2.11 Scenariusz przypadku użycia wyświetlania informacji szczegółowych zasobu
10
Modyfikowanie danych zasobu
Scenariusz opisujący przypadek użycia modyfikacji szczegółów zasobu znajduje się na
rysunku 2.12. Manager wciska przycisku edycji zasobu, w odpowiedzi system wyświetla
formularz. Manager wprowadza uaktualnione dane i wciska przycisk zatwierdzający. System
weryfikuje wprowadzone dane i jeżeli są poprawne to je zmienia i pokazuje komunikat
powodzenia zmian.
Rys. 2.12 Scenariusz główny przypadku użycia modyfikacji danych zasobu
Scenariusz przewiduje również wprowadzenie nieprawidłowych danych. Na rysunku 2.13
widać, że w takim przypadku system wyświetla komunikat i niepoprawnych danych zasobu.
Manager zamykając komunikat ma szanse na poprawienie danych, gdyż znajduje się w oknie
edycji danych.
Rys. 2.13 Scenariusz alternatywny przypadku użycia modyfikacji danych zasobu
Usuwanie zasobu
Aktor manager może usunąć zasób poprzez użycie przycisku usuń zasób. System w
odpowiedzi na żądanie usuwa dane zasobu i wyświetla komunikat o usunięciu zasobu.
Rysunek 2.14 przedstawia scenariusz usuwania zasobu.
Rys. 2.14 Scenariusz przypadku użycia usuwania danych zasobu
11
Potwierdzanie rezerwacji
Jednym z wymagań, które realizuje pracownik jest potwierdzanie rezerwacji. Pracownik na
liście wciska przycisk potwierdzenia wydarzenia, następnie system potwierdza dane
wydarzenia i wyświetla komunikat o potwierdzeniu. W efekcie wydarzenie jest potwierdzone.
Rysunek 2.15 przedstawia opisany scenariusz.
Rys. 2.15 Scenariusz przypadku użycia potwierdzania rezerwacji
Anulowanie rezerwacji
Anulowanie rezerwacji odbywa się analogicznie do jej potwierdzenia, z jedną różnicą. System
anuluje dane rezerwacji oraz wyświetla komunikat jej anulowania. Rysunek 2.16 przedstawia
scenariusz anulowania rezerwacji.
Rys. 2.16 Scenariusz przypadku użycia anulowania rezerwacji
Pozostałe scenariusze
Scenariusze nieopisane w pracy są bardzo podobne do tych opisanych wyżej, dlatego
świadomie nie zdecydowałem się zamieszczać ich opisu. Zaprezentowałem wszystkie
reprezentatywne przypadki scenariuszy przypadków użycia.
1.3. Modelowanie słownika pojęć w narzędziu ReDSeeDS
1.3.1. Tworzenie słownika pojęć w narzędziu ReDSeeDS
Dobrą praktyką jest pogrupowanie pojęć w odpowiednich katalogach, czyli rozdzielenie ich
na opisujące interfejs użytkownika, widoki oraz pojęcia biznesowe. Dodatkowo
wprowadzenie podziału w katalogu interfejsu użytkownika na okna, przyciski i komunikaty.
Co więcej podział ich według zakresu funkcjonalności może również wnieść wyższą jakość
specyfikacji.
Oddzielone pojęcia biznesowe należy uzupełnić o ich atrybuty. W drzewie projektu klikamy
prawym przyciskiem myszy, wybieramy New a następnie Notion. Nadajemy nazwę pojęciu i
12
przypisujemy mu znaczenie. Stworzone pojęcia edytujemy i ustawiamy im typ Attribute oraz
wybieramy rodzaj. Dostępne rodzaje atrybutów opisane są w tabeli 2.2.
Aby nadać pojęciom atrybut należy w widoku projektu chwycić dane pojęcie i przeciągnąć je
na pojęcie typu Concept. W oknie dialogowym wybrać opcję Add as attribute.
Gdy przypniemy do pojęć atrybuty, można przystąpić do stworzenia głównego modelu
dziedziny. W tym celu klikamy prawym przyciskiem myszy na katalog New -> Notions
Diagram. Do utworzonego modelu dodajemy wszystkie pojęcia typu Concept i ich atrybuty.
Widzimy na diagramie relację między pojęciem Concept a Attribute, więc jedyne co
pozostało to stworzenie relacji między pojęciami biznesowymi oraz przypisanie im krotności.
Po wykonaniu powyższych czynności mamy gotowy główny model dziedzinowy.
Pozostało stworzyć resztę modeli – zasada, która pozwoli na opanowanie zakresu dziedziny to
tworzenie jednego modelu wymagań do jednego przypadku użycia. Jest to spowodowane
faktem ograniczenia ilości pojęć na jednym diagramie, gdyż użycie wszystkich pojęć na
jednym może spowodować chaos. Tabela 2.2 przedstawia wykorzystane przeze mnie relacje
między pojęciami i sposób ich interpretacji przez transformatę.
Rodzaj relacji Źródło Cel Interpretacja
Directed Relation SimpleView Concept Obiekt biznesowy z właściwości
którego będzie korzystał widok
Directed Relation SimpleView Attribute Atrybuty odpowiadają polom jakie
zostaną wygenerowane w widoku na
który wskazują
Directed Relation ListView Attribute Atrybuty odpowiadają kolumnom jakie
zostaną wygenerowane w widoku listy
Directed Relation Trigger SimpleView Parametr akcji przy wywołaniu akcji na
przycisku
Directed Relation Screen SimpleView Wykorzystany widok formularza na
ekranie
Directed Relation ListView Screen Wykorzystany widok listy na ekranie
Indirect Relation Trigger Screen Dostępne przyciski na ekranie
Generalization Concept Concept Nie działa
Tab. 2.2 Tabela zawierająca zastosowane typy relacji i sposób ich interpretacji w transformacie
1.3.2. Słownik pojęć dla systemu rezerwacji zasobów
Dziedzina systemu została opisana wieloma modelami. Każdy przypadek użycia ma swój
model dziedziny oraz dodatkowo powstał diagram, który pokazuje zależności między
pojęciami typu Concept. Modele powstałe na podstawie przypadków użycia zawierają
wszystkie pojęcia ze scenariusza danego przypadku użycia. W dalszej części rozdziału
przedstawię kilka z nich, będą to modele dla przypadków użycia, których scenariusze
opisałem w poprzednim rozdziale.
13
Data Model
Na rysunku 2.17 przedstawiony jest główny model dziedziny. Składa się on z pojęć typu
Concept oraz Attributes. Celem modelu jest pokazanie relacji biznesowych między
poszczególnymi pojęciami oraz opisanie ich cech przy pomocy atrybutów.
W wyniku analizy zostały wyodrębnione 4 pojęcia typu Concept przedstawione w tabeli 2.3.
Pojęcie Tłumaczenie Kontekst biznesowy
Employee Pracownik Użytkownik systemu będący jednocześnie pracownikiem
instytucji
Manager Manager Użytkownik systemu będący jednocześnie pracownikiem
instytucji mający prawa do zarządzania zasobami
Resource Zasób Rzecz będąca własnością instytucji, która może zostać
wypożyczona przez pracowników np. projektory, samochody
itp.
Event Rezerwacja Rejestrowane zdarzenie polegające na zarezerwowaniu do
użytku pewnych zasobów na określony czas. Rezerwacja
może odnosić się również do pracowników w kontekście
zorganizowanych spotkań czy wyjazdów służbowych.
Tab. 2.3 Tabela zawierająca pojęcia biznesowe
Pracownik został opisany zestawem niezbędnych atrybutów takich jak:
• Employee name – imię pracownika, atrybut tekstowy
• Employee surname – nazwisko pracownika, atrybut tekstowy
• City – miejsce zamieszkania pracownika, atrybut tekstowy
• Street – ulica na której zameldowany jest pracownik, atrybut tekstowy
• House numer – numer domu pracownika, atrybut tekstowy
• Flat numer – numer mieszkania pracownika, atrybut liczbowy
• Login – login do systemu pracownika, atrybut tekstowy
• Password – hasło do systemu pracownika, atrybut typu Password
• Location – jednostka firmy do której przypisany jest użytkownik, atrybut tekstowy
Manager dziedziczy po pracowniku jego atrybuty, a to co rozróżnia te byty to zakres
funkcjonalny systemu do którego mają dostęp.
Zasób jest opisany atrybutami:
• Name – nazwa zasobu, atrybut tekstowy
• Type – typ zasobu, czyli np. sala, urządzenie itp., atrybut tekstowy
• Location – jednostka firmy w której dostępny jest do wypożyczenia zasób, atrybut
tekstowy
Z kolei rezerwacja opisana jest atrybutami:
14
• Start date – początek rezerwacji, atrybut typu data
• End date – koniec rezerwacji, atrybut typu data
• Status – stan rezerwacji, atrybut tekstowy
Na rysunku 2.17 przedstawione są również relacje i ich krotności, które przedstawiają
zależności między pojęciami biznesowymi. Lista relacji i ich znaczenie:
• Relacja rezerwacja – pracownik -> w wielu rezerwacjach może brać udział wielu
uczestników, którymi są pracownicy
• Relacja manager – pracownik -> manager posiada wszystkie cechy pracownika
• Relacja rezerwacja – zasób -> w wielu rezerwacjach może być rezerwowane wiele
zasobów
Rys. 2.17 Główny diagram dziedziny systemu
Logowanie
Na rysunku 2.18 znajduje się model dziedziny logowania pracownika i managera. Wskazuje
on, że na ekranie logowania będzie dostępny widok z atrybutami login i password
opisującymi pracownika oraz przycisk logowania, który przekazywać będzie dane
uzupełnione w widoku login credentials. W modelu są również komunikaty, przyciski i okna,
które nie są bezpośrednio powiązane z innymi pojęciami – m.in. ekran główny
managera/pracownika oraz komunikat błędnego logowania.
15
Rys. 2.18 Diagram dziedziny logowania pracownika i managera do systemu
Wyświetlanie listy pracowników
Rysunek 2.19 przedstawia model dziedzinowy w zakresie wyświetlania listy pracowników.
Ekran employee data list screen (ekran listy pracowników) składa się z listy pracowników
(ang. employee list) oraz są na nim dostępne 4 przyciski odpowiedzialne za dodawanie,
wyświetlanie, modyfikowanie i usuwanie danych pracownika.
Lista pracowników zawiera obiekty biznesowe typu employee, na której w kolumnach
widoczne będą dane:
• Employee name
• Employee surname
• City
• Street
• House numer
• Flat numer
• Location
• Login
Zawartość atrybutów została wyjaśniona przy okazji głównego modelu dziedzinowego.
16
Rys. 2.19 Diagram dziedziny wyświetlania listy pracowników
Dodawanie pracownika
Rysunek 2.20 przedstawia dziedzinę systemu dla przypadku użycia mającego na celu
stworzenie pracownika. Ekran add new employee screen zawiera przycisk zatwierdzający
tworzenie pracownika, który pobiera wartości z widoku employee data. Widok employee data
odpowiada za wyświetlenie się pól odpowiadających atrybutom pojęcia biznesowego. Atrybut
Password pozwala na stworzenie pola, gdzie każdy wpisany znak jest ukrywany pod znakiem
*.
17
Rys. 2.20 Diagram dziedziny dodawania nowego pracownika
Wyświetlanie informacji szczegółowych zasobu
Model z rysunku 2.21 przedstawia dziedzinę systemu dla przypadku użycia wyświetlania
szczegółów zasobu. Na ekranie resource details screen są dostępne 2 przyciski – do usuwania
zasobu oraz do otworzenia okna modyfikacji zasobu. W oknie dostępny jest widok resource
data, który zawiera 3 atrybuty – nazwę, typ oraz lokalizację.
Rys. 2.21 Diagram dziedziny wyświetlania informacji szczegółowych zasobu
18
Modyfikowanie danych zasobu
Diagram widoczny na rysunku 2.22 pokazuje zależności w dziedzinie systemu z zakresu
modyfikacji danych zasobu. Na ekranie update resource details screen widoczny jest prosty
widok zawierający 3 pola takie jak atrybuty oraz przycisk do zatwierdzenia danych z widoku.
Dodatkowo są 2 komunikaty – sukces oraz błąd w przypadku odpowiednio poprawnej i
błędnej weryfikacji wprowadzonych danych.
Rys. 2.22 Diagram dziedziny modyfikowania informacji szczegółowych zasobu
19
1.4. Generowanie kodu aplikacji
1.4.1. Architektura MVP
MVP jest wzorcem projektowym według którego reguł generowany jest kod przez narzędzie
ReDSeeDS. MVP oznacza odpowiednio Model-View-Presenter. Podział na warstwy jest
bardzo zbliżony do popularniejszego wzorca MVC. MVP opiera się na jasno określonych
zasadach komunikacji między warstwami oraz sprecyzowanych rolach poszczególnych
warstw.
Warstwa prezentera jest najważniejszą warstwą w zastosowanym wzorcu projektowym. To
przez nią przechodzi cała komunikacja między warstwami, gdyż w przeciwieństwie do MVC
warstwa widoku i modelu nie mogą ze sobą bezpośrednio się komunikować. Warstwa
prezentera ma wiedzę o interfejsie graficznym i o tym w jaki sposób ma mapować akcje
wykonywane przez użytkownika na zmiany widoku oraz modelu.
Warstwa widoku odpowiada za wygląd i interakcję z użytkownikiem. Jest w niej
zaimplementowany interfejs graficzny oraz akcje na nim wywoływane. Informacja o każdej
interakcji z GUI jest przekazywane do warstwy prezentera, gdzie wywoływane są
odpowiednie metody z klasy modelu.
Warstwa modelu posiada mocno ograniczoną rolę, mianowicie wykonuje operacje na danych
i przekazuje ich wynik z powrotem do prezentera.
Reasumując, użytkownik ma bezpośredni kontakt z warstwą widoku. W momencie
wywołania akcji na interfejsie graficznym, przesyłane jest żądanie obsługi interakcji z
warstwy widoku do warstwy prezentera. Następnie warstwa prezentera wybiera model do
obsługi żądania i je do niego przekazuje. Wywołany model wykonuje podstawowe operacje
na danych, a wynik zwraca do prezentera. Na koniec prezenter przekazuje otrzymane dane do
warstwy widoku. Rysunek 3.2 pokazuje relacje między warstwami.
Rys. 3.2 Relacje między warstwami we wzorcu MVP
1.4.2. Echo3
Echo3 jest darmową platformą stworzoną przez firmę NextApp do budowy jednoekranowych
aplikacji internetowych, czyli Rich Internet Application[7]. RIA odnosi się do aplikacji, które
oferują dynamiczny jednoekranowy interfejs graficzny, który eliminuje rozwiązania znane z
technologii HTML wymagające częstego ładowania kolejnych stron. Framework Echo3
umożliwia implementację rozwiązania po stronie serwera w języku Java lub po stronie klienta
w języku JavaScript.
Biblioteki Echo3 dostarczają wiele gotowych komponentów, które wykorzystywane są w
warstwie widoku generowanej aplikacji. W prosty sposób na bazie dostępnych komponentów
można tworzyć własne – wystarczy stworzyć klasę dziedziczącą po klasie komponentu i w
niej ustawić odpowiednie parametry. Na rysunku 3.1 znajduje się przykład przycisku
MyButton zbudowanego na komponencie Echo3 Button.
20
Rys. 3.1 Przykład przycisku zbudowanego na komponencie Echo3
1.4.3. Proces generowania kodu
Po przygotowaniu przypadków użycia i modeli dziedziny, można przejść do wygenerowania
kodu aplikacji. Przy generowaniu kodu narzędzie ReDSeeDS korzysta z funkcjonalności
dostarczanej przez API Enterprise Architect’a lub Modelio, dlatego jedno z tych narzędzi
musi być zainstalowane na komputerze.
Należy pamiętać, by przed przystąpieniem do generowania kodu przeprowadzić walidację
specyfikacji – prawy przycisk myszy na katalogu Requirements Specification -> Validate. Po
ukończonej walidacji w zakładce Problems wyświetlą się informacje oraz wykryte błędy. Do
czasu aż specyfikacja będzie zawierała błędy, nie będzie możliwości poprawnego
wygenerowania kodu.
Po naprawie ewentualnych błędów należy wykonać powyższe czynności ponownie, a
następnie prawym przyciskiem myszy kliknąć na Requirements Specification, ale tym razem
wybrać Generate -> From RSL to Java. Wyświetli się okno dialogowe i będzie generowany
kod aplikacji. Potrwa to parę minut, w zależności od złożoności projektu – dla projektu, który
zawierał 18 przypadków użycia, kod generował się około 4 minut.
Wygenerowany kod aplikacji znajduje się w katalogu Code. Jego struktura bazuje na wzorcu
MVP oraz wykorzystuje framework Echo3 oraz Spring.
Klasy stworzone w warstwie prezentera odpowiadają przypadkom użycia, dlatego należy
pamiętać by w nazwach przypadków użycia nie używać polskich znaków ani znaków
specjalnych, gdyż kod aplikacji się nie skompiluje.
W warstwie widoku wygenerowane klasy dzielą się na 3 pakiety: auxiliary, messages, screens.
Pakiet auxiliary zawiera klasy związane z budową widoków ListView. Pakiet messages
zawiera klasy okien dialogowych, czyli okna komunikatów oraz wyboru dat. Ostatni z
pakietów, screens, posiada klasy ze zdefiniowanymi oknami aplikacji.
Wygenerowany kod warstwy modelu zawiera interfejs i klasę go implementującą. Są w niej
wygenerowane szkielety metod, które zostały zidentyfikowane na bazie stworzonych
scenariuszy przypadków użycia.
Ostatnim z pakietów jest pakiet dto, który zawiera klasy obiektów DTO. Klasy te są tworzone
na bazie pojęć typu Concept, SimpleView i ListView oraz ich atrybutów. O ile pojęcia typu
Concept oraz SimpleView mają zwykły postfix DTO, o tyle obiektem DTO listy jest opis jego
pojedynczego wiersza. Nazwa klasy dla obiektu będącego wierszem listy zawiera postfix
ListItemDTO.
21
1.4.4. Różnice w generowanym kodzie między wersjami narzędzia ReDSeeDS
Z racji na fakt, że w wersji narzędzia ReDSeeDS 0.6.5 miałem problemy z wygenerowanym
kodem, by doprowadzić go do działania, postanowiłem wygenerować go również w wersji
0.6.4. Zauważyłem przy tym szereg różnic między wersjami, które w tym rozdziale
chciałbym po krótce opisać.
Pierwszą różnicą i zarazem najbardziej szokującą było to, jak szybko aplikację z
wygenerowanym kodem starszej wersji ReDSeeDS’a doprowadziłem do działania. Właściwie
brakowało w niej kilku importów klas, by było możliwe przejście między wszystkimi
ekranami. Nad kodem pochodzącym z transformaty 0.6.5. spędziłem co najmniej kilkukrotnie,
a nawet kilkunastokrotnie więcej czasu.
Jednym z czynników wpływającym na tę różnicę czasu były braki w wygenerowanym kodzie.
W przeciwieństwie do poprzedniej wersji narzędzia, aktualna nie wygenerowała kompletnie
pakietu DAO, natomiast warstwa modelu była okrojona do pustego interfejsu i klasy go
implementującej – trzeba było samemu generować metody w warstwie modelu.
Kolejną różnicą był kod w warstwie prezentera. Starsza wersja narzędzia generowała interfejs
IPresenter, natomiast w wersji 0.6.5. generowana jest klasa abstrakcyjna
AbstractUseCasePresenter. Różnica ta wynika z tego, że kod pochodzący z wersji 0.6.5.
wykorzystuje framework Spring i właśnie ta klasa implementuje interfejs BeanFactoryAware
pochodzący z biblioteki Spring.
Różnią się również nazwy klas i interfejsów każdej z trzech warstw. Począwszy na warstwie
prezentera a kończąc na warstwie widoku. Tabela 2.4 przedstawia różnice w nazewnictwie.
Warstwa/Obiekt ReDSeeDS 0.6.4 ReDSeeDS 0.6.5
Model IModel, ModelImpl IService, ServiceImpl
View VNazwaScreen,
VNazwaMessage
NazwaScreen, NazwaMessage
Presenter PNazwa NazwaPresenter
DTO XNazwa NazwaDTO
Tab. 2.4 Tabela z podstawowymi różnicami w nazewnictwie klas w rozbiciu na poszczególne warstwy
Zmianą na lepsze można nazwać podział warstwy widoku na pakiety, który pojawił się w
wersji 0.6.5. Klasy podzielone są na 3 pakiety, w przeciwieństwie do poprzedniej wersji,
gdzie wszystkie klasy widoku były w jednym pakiecie. Mało tego, wersja 0.6.5. obsługuje
również widok listy, czego nie potrafi starsza wersja transformaty. Wracając, widok jest
podzielony na pakiety – auxiliary, messages, screens. Pakiet auxiliary zawiera klasy
odpowiedzialne za budowanie widoków list, pakiet messages zawiera wszystkie klasy
komunikatów, natomiast pakiet screens ekranów.
Ostatnią różnicą, którą zauważyłem to sposób w jaki wykorzystywane są teksty. W
transformacie ReDSeeDSa 0.6.4. teksty były na sztywno wpisywane za każdym razem do
elementów interfejsu, natomiast w wersji 0.6.5. zmieniło się to podejście na wykorzystanie
klasy ResourceBundle. Różnica polega na tym, że wszystkie teksty są skupione w pliku
*.properties i za pomocą klasy ResourceBundle wykorzystywane są odpowiednie pojęcia.
Pozwala to na minimalizację ilości napisów oraz umożliwia zarządzanie wszystkimi napisami
22
z jednego miejsca w projekcie. Kod pozbawiony na sztywno wpisanych tekstów staje się
czytelniejszy, a co za tym idzie polepsza się jego jakość.
23
2. Praca nad wygenerowanym kodem
2.1. Modyfikacje obiektów DTO
Jedna z modyfikacji jaką dokonałem w wygenerowanym kodzie była inwentaryzacja i
wynikająca z niej minimalizacja ilości klas DTO. Zauważyłem, że w zdecydowanej
większości przypadków korzystam z tego samego zakresu danych, dostarczanego przez
poszczególne obiekty DTO. Nie widząc potrzeby utrzymywania zestawu 3 różnych klas
przechowujących identyczne dane, pozostawiłem tylko jedną. W taki sposób zniwelowałem
ilość klas z 9 do 3. Tabela 4.1 przedstawia połączenie klas.
Klasa wyjściowa Klasy pierwotne
EmployeeDTO EmployeeDTO, EmployeeDataDTO, EmployeeListItemDTO
EventDTO EventDTO, EventDataDTO, EventListItemDTO
ResourceDTO ResourceDTO, ResourceDataDTO, ResourceListItemDTO
Tab. 4.1 Tabela przedstawiająca translację klas DTO
Kolejną modyfikacją było usunięcie klasy ManagerDTO. Problem rozróżnienia użytkownika
jest rozwiązywany w momencie autoryzacji i sprawdzeniu flagi w bazie danych, a
użytkownicy są przechowywani w obiekcie EmployeeDTO.
Stworzyłem klasę o nazwie LocationDTO, która ma za zadanie przechowywać dane o
lokalizacji: id i nazwę. Pierwotnie z dziedziny systemu wynika, że Resource i Employee mają
atrybut location typu String. Jednakże skoro skatalogowane są w bazie danych lokalizacje w
postaci id i nazwa, to warto przechowywać je w oddzielnym obiekcie. Obiekty stworzonej
klasy wykorzystywane są właśnie w tych klasach w zamian za obiekt String. Z tego samego
względu stworzyłem klasę StatusDTO, która wykorzystywana jest z kolei w klasie EventDTO
i przechowuje id i nazwę statusu rezerwacji.
Klasa EventDTO uległa rozszerzeniu o 2 listy, które przechowują obiekty EmployeeDTO oraz
ResourceDTO. Jako, że funkcjonalność systemu umożliwia dodanie kilku użytkowników i
zasobów do jednej rezerwacji, konieczne było rozszerzenie klasy.
Powyższe modyfikacje pomogły w uporządkowaniu zakresu systemu. Minimalizacja ilości
takich samych klas oraz rozwinięcie o dodatkowe, przechowujące informacje o lokalizacji i
stanie, umożliwiło łatwiejsze zarządzanie obiektami. Wydaje mi się, że te poprawki
przyniosły mniejszy koszt utrzymania systemu, gdyż przed nimi było 11 klas, a obecnie jest
ich 6 i obejmują szerszy zakres. Na rysunku 4.1 zaprezentowane są klasy przed oraz po
modyfikacjach.
24
Rys. 4.1 Po lewej stronie wygenerowane klasy DTO, po prawej klasy po zastosowanych modyfikacjach
2.2. Modyfikacja kodu w warstwie modelu
W warstwie modelu wygenerowany został jeden pakiet app.model w którym są 2 klasy i jeden
interfejs. W dalszej części tego podrozdziału omówię jak wyglądał kod oraz co w nim
zmieniłem.
Klasa ServiceFactory
Klasa ServiceFactory bezpośrednio po wygenerowaniu kodu wyglądała tak jak przedstawia to
rysunek 4.2. Jej rola ograniczała się do podstawowych operacji na modelu. Mimo swojej
prostoty, kod zawierał błędy, które musiałem poprawić, by klasa mogła się skompilować.
Rys. 4.2 Kod klasy ServiceFactory.java przed poprawkami
Błędem był nieprawidłowy kod do inicjalizacji obiektu w linii nr 5, przez który również
metoda getService wskazywała na błąd. Poprawka sprowadziła się do podmiany typu void na
IService, natomiast człon po znaku ‘=’ rozdzieliłem na new ServiceImpl() – dzięki tej
modyfikacji wygenerowany kod w klasie ServiceFactory mógł się poprawnie skompilować.
Rysunek 4.3 przedstawia kod po wprowadzonej poprawce.
Rys. 4.3 Kod po wprowadzonej poprawce
25
Interfejs IService
Interfejs warstwy modelu wygenerował się z pustą zawartością, mimo że metody z tej
warstwy były wykorzystywane w kodzie. Główną pracą do wykonania było zatem
wygenerowanie metod, które znajdowały się w kodzie. W związku z rozszerzeniem
funkcjonalności dodałem kilka metod własnych, które były niezbędne by pokryć
funkcjonalność dodatkową. Łącznie powstało 26 metod, które przedstawione są na rysunku
4.4.
Rys. 4.4 Spis metod warstwy modelu
Oprócz wygenerowania metod, wprowadziłem dla nich kilka modyfikacji dotyczących
zwracanego wyniku oraz parametrów jakie przyjmują. Metody validateEmployeeData,
validateResourceData oraz validateEventData w wygenerowanym kodzie były typu int,
natomiast po inwentaryzacji stwierdziłem, że wartość typu boolean jest wystarczająca, więc
metodom tym zmieniłem ich typ na boolean.
Metody służące do usuwania danych, czyli deleteEmployeeData i deleteResourceData,
zostały zmienione pod kątem parametru jaki przyjmują. W wygenerowanym kodzie za
parametr przyjmowały obiekt odpowiednio EmployeeDataDTO i ResourceDataDTO,
jednakże wystarczającym parametrem jest id, które jest unikalne, dlatego metody te przyjmują
za parametr Long employeeID lub Long resourceID.
Stworzyłem między innymi takie metody jak readEmployee, readResource oraz readEvent,
gdyż potrzebowałem metod, które pobiorą dane o jednym pracowniku, zasobie, rezerwacji w
celu wyświetlenia ich w oknie szczegółów oraz formularzu do edycji danych. Tak jak metody
do usuwania, tak też te do odczytu przyjmują za parametr id, dzięki któremu można określić
jednoznacznie jakie dane mają zostać pobrane.
Interfejs musiałem dodatkowo rozwinąć o dwie niezbędne metody do potwierdzania i
anulowania rezerwacji. Pierwotnie wygenerowany kod w tym celu stosował metodę
26
updateEventData, gdyż nazwy metod są budowane na bazie ActionType zdania scenariusza
przypadku użycia (Rys. 2.15, 2.16). Z uwagi na fakt, że potwierdzanie i anulowanie
rezerwacji wiąże się tylko i wyłącznie ze zmianą stanu takowej rezerwacji, nie widząc sensu
budowy wielkiej metody od wszystkiego co związane z modyfikacją rezerwacji,
zdecydowałem się na stworzenie dwóch granularnych metod, które za parametr przyjmują id
rezerwacji.
Z racji na fakt, że założeniem systemu było wprowadzenie dostępności zasobów w zależności
od lokalizacji, stworzyłem metody do jej obsługi. Metoda getLokaID przyjmuje za parametr
login (który jest unikalny w systemie) i na jego podstawie pobiera id lokalizacji, do której jest
przypięty zalogowany użytkownik. Następnie lokalizacja jest wykorzystywana w metodach
do pobrania możliwych do rezerwacji pracowników i zasobów – readEmployeeListForEvent,
readResourceListForEvent.
Klasa ServiceImpl
Jest to klasa implementująca interfejs IService, która po wygenerowaniu była również pusta.
Po utworzeniu wszystkich potrzebnych metod w interfejsie, wygenerowałem metody w klasie
ServiceImpl, które następnie uzupełniłem o logikę biznesową.
Metody odpowiedzialne za pobieranie list lub informacji o pojedynczym obiekcie
biznesowym nie są ciekawe, gdyż wszystkie wyglądają jednorodnie. Tworzona jest w nich
instancja DAO, a następnie wywoływana jest metoda z pakietu app.dao, która w zależności
od potrzeb zwraca odpowiednie dane. Przykładowy kod takich metod znajduje się na rysunku
4.5 oraz 4.6.
Rys. 4.5 Metoda z warstwy modelu odpowiedzialna za pobranie listy pracowników
Rys. 4.6 Metoda z warstwy modelu odpowiedzialna za pobranie informacji o pracowniku
Metody, które służą do walidacji są już ciekawsze, gdyż są bardziej złożone. Sprawdzane są
między innymi pod względem wypełnień pól wymaganych oraz czy nie kolidują z
istniejącymi danymi.
Jedną z metod służących do weryfikacji jest validateLoginCredentials. Jest ona
wykorzystywana do sprawdzenia danych logowania użytkownika. Jako parametr otrzymuje
obiekt LoginCredentialsDTO, który zawiera login oraz hasło podane przy logowaniu. Metoda
na początku pobiera dane z powyższych pól i wywołuje metodę do walidacji z pakietu
app.dao, gdzie sprawdzana jest poprawność danych oraz rodzaj użytkownika – czy konto
managera czy pracownika. W przypadku, gdy pola nie zostaną uzupełnione metoda zwróci
wartość 0, co jest interpretowane jako niepowodzenie. Jeżeli natomiast metoda zwróci
wartość 1 lub 2, wtedy odpowiednio oznacza to, że użytkownik jest managerem bądź
pracownikiem. Rysunek 4.7 przedstawia implementację opisywanej metody.
27
Rys. 4.7 Metoda służąca do autoryzacji użytkownika przy logowaniu
Metoda do walidacji danych użytkownika, czyli validateEmployeeData, jest trochę bardziej
rozbudowana. Pobiera ona dane z parametru wejściowego, jednakże odczyt danych jest w
klauzuli do wyłapania wyjątku NullPointerException, który może pojawić się, gdy nie
zostanie wybrana lokalizacja (locationID będzie null). Jeżeli sytuacja taka będzie miała
miejsce, metoda zwróci wartość false. Następnie sprawdzane jest, czy wszystkie z
wymaganych pól (wymagane pola są wszystkie, prócz flatNumber) są uzupełnione. Jeżeli nie,
walidacja również będzie niepomyślna. Na sam koniec sprawdzany jest dodatkowo
wprowadzony login, czy nie koliduje z istniejącymi już w systemie, gdyż musi być on
unikalny. Jeżeli nie istnieje użytkownik o podanym loginie, metoda zwraca true i użytkownik
będzie mógł zostać założony w systemie. Rysunek 4.8 przedstawia implementację metody
validateEmployeeData.
Rys. 4.8 Metoda służąca do walidacji danych użytkownika
28
Jednakże najciekawszą metodą z warstwy modelu jest walidacja rezerwacji, ze względu na
możliwość wyboru kilku użytkowników i zasobów w jednej rezerwacji. Metoda
validateEventData odpowiada za sprawdzenie, czy wszystkie rezerwowane zasoby są w
wybranym czasie dostępne czy nie. Jednym z głównych założeń rezerwacji jest to, że każda
rezerwacja musi mieć przypisaną chociaż jednego użytkownika. Ma to na celu rozwiązanie
sytuacji, że pracownik ‘widmo’ wypożyczy zasób i nigdy go nie zwróci, gdyż w systemie nie
byłoby informacji o pracowniku. Rysunek 4.9 pokazuje pełny obraz zaimplementowanej
metody.
Metoda validateEventData odczytuje dane z pól parametru wejściowego. Następnie data
rozpoczęcia i zakończenia wydarzenia jest konwertowana na format yyyy-mm-dd. Jeżeli
metoda nie będzie w stanie wykonać parsowania, wywołany zostanie wyjątek ParseException,
a metoda zwróci niepowodzenie. Dzięki funkcji porównania dat dostępnej w standardowej
bibliotece Javy w łatwy sposób sprawdzane jest, czy data rozpoczęcia jest wcześniejsza od
daty zakończenia. Następnie wykonywana jest próba pobrania pierwszego użytkownika –
czyli sprawdzenie czy został wybrany, by rozwiązać sytuację opisaną wyżej. Pod koniec
sprawdzane jest, czy każdy rezerwowany użytkownik i zasób są wolne we wskazanym
terminie, jeżeli jakikolwiek z zasobów nie jest dostępny, zwracany jest wynik false.
29
Rys. 4.9 Metoda służąca do sprawdzenia poprawności danych i dostępności zasobów w rezerwacji
2.3. Modyfikacja kodu w warstwie prezentera
Pakiet główny – app.presenter
W klasach pakietu app.presenter wykonałem parę prostych modyfikacji kodu. Główną
zmianą była rezygnacja z zastosowania framework’a Spring w aplikacji. Podjętą decyzję
motywuję tym, że nigdy wcześniej nie miałem styczności ze Springiem i nie potrafiłem
przygotować poprawnej konfiguracji. Na rysunku 4.10 przedstawiam metodę do inicjalizacji
instancji aplikacji wykorzystującej Spring, natomiast na rysunku 4.11 znajduje się kod
metody po modyfikacji.
30
Rys. 4.10 Metoda do stworzenia instancji aplikacji z użyciem framework’a Spring
Rys. 4.11 Metoda do stworzenia instancji aplikacji po modyfikacji
W klasie MainPresenter zmiany, które dokonałem są również związane z frameworkiem
Spring. Mianowicie ciała metod invokeSignInAsEmployee i invokeSignInAsManager
wykorzystywały możliwości ww. platformy, a modyfikacja polegała na zmianie kodu na taki,
który korzysta z Echo3. Metoda po zmianie na początku inicjalizuje widok poprzez pobranie
aktualnie wyświetlanego, a następnie jest na nim wywoływana metoda, której zadaniem jest
wyświetlenie ekranu logowania. Rysunki 4.12 i 4.13 pokazują przykładowy kod odpowiednio
przed i po modyfikacji.
Rys. 4.12 Metoda do wywołania przypadku użycia logowania pracownika z użyciem framework’a Spring
Rys. 4.13 Metoda do wywołania przypadku użycia logowania pracownika po modyfikacji
Na rysunku 4.13 widać jeszcze jedną zmianę, mianowicie metoda dostaje jako parametr
obiekt ResourceBundle, o którym wspominałem w rozdziale 2.4.2, który dotyczył różnic w
generowaniu kodu transformat kolejnych wersji narzędzia ReDSeeDS.
W klasie abstrakcyjnej AbstractUseCasePresenter również wprowadziłem modyfikację, która
polegała na ustawieniu zmiennej widoku. W aplikacji przy wywołaniu metody
closeCurrentPageAndFinalizeUseCase występował wyjątek NullPointerException. Problem
polegał na tym, że zmienna odpowiedzialna za przechowywanie aktualnego widoku, była
równa null i w momencie, gdy program wykonywał na nim metodą generowany był wyjątek.
Rozwiązaniem było przed wywołaniem metody na widoku ustanowienie wartości na nim
poprzez pobranie aktualnego widoku. Kod z rysunku 4.14 pokazuje metodę po zmianie.
Rys. 4.14 Metoda do zamykania okna, kolorem żółtym oznaczona jest dodana linia kodu
31
Logowanie
W pakiecie app.presenter.signin wygenerowane zostały dwie klasy odpowiadające
zamodelowanym przypadkom użycia. Już w rozdziale 2.1.2 zasygnalizowałem problem z
jakim się spotkałem, a czego efektem są dwie klasy prezentera – jedna dla logowania jako
pracownik, druga dla logowania jako manager. Jako że moim celem jest ograniczenie ilości
klas do niezbędnego minimum, stąd zamiast dwóch klas zostawiłem jedną.
Powstała klasa o nazwie SignInPresenter, która łączy w sobie funkcjonalność obydwu,
minimalizując przy tym ilość napisanego kodu. Zamiast 154 linii kodu, jest tylko 98. Takie
połączenie niesie za sobą kolejny plus, w przypadku rozbudowy systemu o kolejną rolę nie
będzie potrzeby tworzenia kolejnej klasy, a wystarczy dodać warunek w metodzie
signInButtonTriggered. Na rysunku 4.15 przedstawiona jest wspomniana metoda.
Metoda signInButtonTriggered jest wywoływana w momencie wciśnięcia przycisku
logowania. W jej ciele wywoływana jest metoda z warstwy modelu validateLoginCredentials,
która zwraca zmienną typu int. Następnie wywoływana jest metoda, która pobiera lokalizację
logowanego użytkownika. W przypadku, gdy metoda odpowiedzialna za autoryzację
użytkownika zwróci wartość 2, wywoływana jest metoda warstwy widoku, której celem jest
wyświetlenie ekranu głównego managera. Dla wartości równej 1 wywoływana jest metoda do
wyświetlenia ekranu głównego pracownika, a gdy nie jest to wartość 1 ani 2, wyświetlany jest
komunikat błędnych danych logowania.
Rys. 4.15 Metoda wywoływana w momencie wciśnięcia przycisku logowania
Zarządzanie pracownikami i zasobami
W tym rozdziale opiszę modyfikacje jakich dokonałem w pakiecie zarządzania pracownikami
oraz zarządzania zasobami. Jako że te dwa pakiety są identyczne tylko korzystają z innych
obiektów DTO oprę te modyfikacje na klasach zarządzania pracownikami.
Pierwszą modyfikacją zastosowaną dla każdej metody *ButtonTriggered, czyli metody
wywoływanej w efekcie wciśnięcia przycisku, było ustawienie zmiennej widoku, tak by nie
wskazywała na null. Problem i jego rozwiązanie opisałem już wcześniej w tym rozdziale, gdy
opisywałem modyfikacje w metodzie closeCurrentPageAndFinalizeUseCase klasy
32
AbstractUseCasePresenter, jednak pozwolę raz jeszcze zaprezentować to rozwiązanie na
rysunku 4.16, na którym znajduje się kod metody addANewEmployeeButtonTriggered.
Rys. 4.16 Pierwsza linia ciała metody prezentuje sposób na inicjalizację zmiennej widoku
Jedną z dostępnych funkcjonalności jest usuwanie pracownika, które tak jak można było
zauważyć na diagramie przypadków użycia (Rys. 2.3) jest dostępne z poziomu dwóch okien.
Jednym z nich jest okno wyświetlenia szczegółów o pracowniku, drugie natomiast to widok
listy pracowników. Wygenerowana w wyniku transformaty metoda
deleteEmployeeButtonTriggered funkcjonalnością pasowała do usuwania z poziomu widoku
listy, a brakowało metody, która przy usunięciu wyświetliłaby poprzedni ekran.
Potrzeba ta jest uzasadniona tym, że skoro wyświetlone są na ekranie szczegóły pracownika i
przyciskiem usuwamy tego pracownika, to nie powinien wyświetlać się po usunięciu wciąż
ten sam ekran, gdyż dane w nim zawarte już nie istnieją. Jako że widok listy jest widokiem
poprzedzającym okno szczegółów to zdecydowałem się zaimplementować metodę, która
wykona tę samą akcję, ale z dodatkowym cofnięciem się do listy pracowników. Rysunek 4.17
przedstawia zaimplementowaną metodę.
Rys. 4.16 Metoda wywoływana po wciśnięciu przycisku usunięcia pracownika z ekranu szczegółów
Kolejną modyfikacją była edycja metody getEmployeeListDTO w klasie
DisplayEmployeeListPresenter. Zamiast zwracać wynik this.employeeListDTO, wywołuje ona
metodę z warstwy modelu i zwraca jej wynik. Wynikiem jest lista wszystkich pracowników.
Natomiast w klasie AddANewEmployeePresenter stworzyłem metodę, która wywołuje metodę
z warstwy modelu do pobrania listy lokalizacji, a następnie ją zwraca.
W klasie UpdateEmployeeDetailsPresenter metoda updateEmployeeButtonTriggered oprócz
wspomnianej wcześniej poprawki inicjalizacji zmiennej widoku, zmodyfikowana została o
warunek na podstawie którego wyświetlana jest stosowna treść. Mianowicie od wyniku
walidacji danych pracownika zależy czy dane pracownika zostaną zmienione i wyświetli się
komunikat sukcesu, czy też wyświetli się sam komunikat błędu. Kod z rysunku 4.17
przedstawia implementację wspomnianej metody.
33
Rys. 4.17 Metoda z instrukcją warunkową uzależnioną od wyniku walidacji wprowadzonych danych pracownika
Rezerwacje
Pakiet app.presenter.resourceBooking w którym znajdują się klasy warstwy prezentera
rezerwacji wymagały również pewnych modyfikacji. Metodyka zmian była identyczna jak w
przypadku innych klas tej warstwy.
Tradycyjnie metody wywoływane wciśnięciem przycisku *ButtonTriggered zostały
rozbudowane o linijkę kodu z rysunku 4.18 do inicjalizacji zmiennej widoku.
Rys. 4.18 Linia kodu do pobrania aktywnego widoku
Klasa AddNewEventPresenter została rozwinięta o dwie metody – getEmployeeListDTO oraz
getResourceListDTO. Na rysunku 4.19 przedstawiona jest metoda getEmployeeListDTO.
Metody jako parametr przyjmują obiekt Long, który jest id lokalizacji. Jako wynik metody
zwracają listę odpowiednio pracowników i zasobów występujących w podanej lokalizacji.
Rys. 4.19 Metoda getEmployeeListDTO po modyfikacji
Metoda createNewEventButtonTriggered uległa identycznej zmianie jak metoda z rysunku
4.17. Został w niej zainicjalizowany widok oraz zastosowałem instrukcję warunkową. Jeżeli
dane zostały zwalidowane prawidłowo to tworzona jest nowa rezerwacja oraz wyświetlany
jest komunikat sukcesu, w przeciwnym razie wyświetlany jest komunikat błędnych danych,
które użytkownik może poprawić i ponownie wywołać walidację.
W uwagi na fakt, że potwierdzić i anulować rezerwację można z dwóch widoków, to klasy
ConfirmEventPresenter oraz CancelEventPresenter zostały rozbudowane o dodatkową
metodę. Zastosowanie ma ona w przypadku, gdy wymagane jest po użyciu opcji cofnięcie
użytkownika o ekran. Jej działanie różni się od wygenerowanej metody tym, że zamyka ona
aktualnie otwarte okno. Sposobem implementacji nie różnią się one od metody z rysunku 4.16,
gdzie zastosowane są dwie kluczowe linie kodu: view.closeCurrentPage() oraz pageClosed().
34
2.4. Modyfikacja kodu w warstwie widoku
Pakiet główny – app.view
W interfejsie IView wygenerowały się wszystkie metody warstwy widoku aplikacji. Za
parametr przyjmowały odpowiednie obiekty prezentera. Zdecydowałem się ujednolicić
sposób wywoływania klas. Nie zauważyłem potrzeby przekazywania obiektu prezentera do
warstwy widoku, więc zrezygnowałem z tego parametru w zamian za obiekt ResourceBundle
oraz w niektórych metodach obiekt Long będący numerem identyfikacyjnym lokalizacji,
pracownika lub zasobu.
Kolejną zmianą była poprawka błędnie wygenerowanego kodu metody show z klasy
ViewImpl. Metoda bezpośrednio po wygenerowaniu wyglądała tak jak na rysunku 4.20.
Należało w niej zmienić w ciele metody zmienną page na parametr metody, czyli
contentPane. Kod na rysunku 4.21 przedstawia poprawioną metodę.
Rys. 4.20 Wygenerowana metoda show
Rys. 4.21 Metoda show po modyfikacji
Klasa ViewImpl wymagała poprawek dotyczącej wyświetlania komunikatów. Zawsze gdy
system miał wyświetlić okno dialogowe z treścią komunikatu, zmienna na której
wywoływana była metoda była równa null, przez co generowany był wyjątek
NullPointerException. Rozwiązaniem problemu była zamiana obiektu na metodę pobierającą
aktualny stan obiektu. Rysunek 4.22 przedstawia metodę, która generowała wyjątek,
natomiast na rysunku 4.23 znajduje się metoda po wprowadzonej modyfikacji.
Rys. 4.22 Wygenerowana metoda do wyświetlenia komunikatu błędnych danych zasobu
Rys. 4.23 Metoda do wyświetlenia komunikatu błędnych danych zasobu po modyfikacji
Ostatnią modyfikacją wprowadzoną w pakiecie app.view było stworzenie pliku
labels.properties, który powinien zostać stworzony przez generator kodu narzędzia
ReDSeeDS. Jako że wygenerowany kod aplikacji wykorzystuje możliwości klasy
ResourceBundle, to plik *.properties jest niezbędny do poprawnego funkcjonowania aplikacji.
Na rysunku 4.24 znajduje się fragment wspomnianego pliku.
35
Rys. 4.24 Fragment pliku labels.properties
Plik labels.properties powinien zawierać zestaw wykorzystywanych tekstów. Każda linia
pliku to kolejny tekst. Niestety przez brak tego pliku w wygenerowanym kodzie, musiałem od
nowa nadawać wszystkie nazwy obiektom interfejsu graficznego, a było ich 107. Jednakże
najbardziej odczuwalna była utrata treści komunikatów opisanych w słowniku pojęć w
narzędziu ReDSeeDS.
Pakiet auxiliary
Pakiet app.view.auxiliary zawiera modele budowanych widoków list w aplikacji. Do budowy
list wykorzystywane są komponenty dostarczane przez framework Echo3. W związku z
rozbudową funkcjonalności w stosunku do dziedziny systemu stworzyłem 3 nowe klasy.
Jedną z nowoutworzonych klas jest LocationListTableModel, czyli model listy lokalizacji.
Lista jest wykorzystywana w dodawaniu i modyfikacji pracownika oraz zasobu. Złożona jest
z dwóch kolumn – unikalnego numeru identyfikacyjnego lokalizacji oraz nazwy lokalizacji.
Kolumny są nazwane odpowiednio Id oraz LocationName. Na rysunku 4.25 przedstawiona
jest metoda getValueAt zwracająca zawartość kolumny wiersza.
Rys. 4.25 Metoda getValueAt z klasy LocationListTableModel
Pozostałe dwie klasy stworzone zostały z myślą o wyborze pracowników i zasobów w
dokonywanej rezerwacji. Klasy nazwałem odpowiednio EmployeePartEventTableModel oraz
ResourcePartEventTableModel. Wszystkie istniejące w projekcie modele list są w zasadzie
takie same, a różnią się tylko ilością i zawartością kolumn. Nie zdecydowałem się użyć
gotowych modeli list pracownika i zasobu, gdyż wiele wystawionych kolumn jest zbędnych
dla osoby tworzącej rezerwację oraz łamałoby ustawę o ochronie danych osobowych.
Zarówno lista pracowników jak i zasobów składa się z 3 kolumn – pierwsza zawiera
informacje o id, imieniu i nazwisku pracownika, natomiast druga id, nazwie i typie zasobu.
Kolejną wprowadzoną modyfikacją w tym pakiecie było usunięcie zduplikowanego kodu.
Transformata narzędzia ReDSeeDS w wersji 0.6.5 w klasie eventListTableModel
36
wygenerowała zduplikowane wszystkie kolumny oprócz id rezerwacji. Ten błąd dotknął 3
metod: getColumnCount, getColumnName, getValueAt. Na rysunku 4.26 znajduje się metoda
getColumnName bezpośrednio po wygenerowaniu kodu.
Rys. 4.26 Metoda getColumnName zawierająca duplikaty
Ostatnią dokonaną zmianą było zwiększenie ilości kolumn w liście rezerwacji o nazwę
rezerwacji, listę pracowników oraz listę zasobów. O ile nazwa rezerwacji jest zwykłym
obiektem String, tak listy pracowników i zasobów do prezentacji w liście sklejane są w ciąg
znaków oddzielonych przecinkiem. Rysunek 4.27 przedstawia odpowiedzialną za to metodę
getValueAt.
Rys. 4.27 Metoda getValueAt po rozwinięciu o dodatkowe kolumny
37
Pakiet messages
W pakiecie app.view.messages w każdej z klas generowały się duplikaty kodu związanego z
przyciskiem ‘Ok’ w oknie dialogowym komunikatu. Rekordowa ilość duplikatów była w
klasie LoginFailedMessage i była równa 55! Wydaje mi się, że jest to czynnik losowy, gdyż
każda z klas komunikatu zawiera inną liczbę zduplikowanego kodu. Tabela 4.2 przedstawia
podstawowe miary związane z duplikowaniem kodu, gdzie miarami są:
• I1 – ilość duplikatów
• I2 – ilość linii wygenerowanej klasy
• I3 – ilość linii klasy po usunięciu duplikatów
Nazwa klasy I1 I2 I3
EmployeeDeletedMessage 10 201 85
EventCanceledMessage 19 309 84
EventConfirmedMessage 18 297 85
LoginFailedMessage 55 741 85
ResourceDeletedMessage 4 129 85
SuccessAddEmployeeMessage 12 225 85
SuccessAddEventMessage 22 345 85
SuccessAddResourceMessage 6 153 85
SuccessEmployeeUpdateMessage 9 189 85
SuccessEventUpdateMessage 20 321 85
SuccessResourceUpdateMessage 3 117 85
WrongEmployeeDataMessage 21 333 85
WrongEventDataMessage 42 585 85
WrongResourceDataError 6 153 85
WrongResourceDataMessage 3 117 85
ŚREDNIO: 17 281 85
Tab. 4.2 Tabela ze statystykami powtórzeń generowanego kodu
Jak wynika z danych zaprezentowanych w tabeli 4.2, średnia długość klasy wynosiła 281 linii,
podczas gdy doprowadzona do poprawności klasa ma 85 linii. Zachowanie transformaty w
tym przypadku jest bardzo niejasne, dlatego grupa SMOG[8] tworząca narzędzie ReDSeeDS
powinna zbadać wnikliwie temat. Pisząc zduplikowany kod, mam na myśli inicjalizację
38
obiektu Button, przypisanie temu obiektowi pewnych cech oraz instrukcję warunkową w
metodzie actionPerformed.
Pakiet screens
W pakiecie w którym znajdują się klasy interfejsów graficznych aplikacji, również
dokonywałem modyfikacji. Głównie polegały one na podmianie pola TextField na komponent
Label lub zaprojektowany wcześniej model listy.
W oknach do tworzenia nowego pracownika i zasobu pole tekstowe lokalizacji zostało
zamienione na wybór lokalizacji z listy. Lista jest jednokrotnego wyboru, gdyż założeniem
systemu jest, by pracownik ani zasób nie były dostępne w wielu lokalizacjach. Definicji listy
jednokrotnego wyboru odpowiada kod zaprezentowany na rysunku 4.28.
Rys. 4.28 Ustawienie listy jednokrotnego wyboru
By zapewnić możliwość wyboru lokalizacji z listy, trzeba ją zapełnić treścią. W tym celu
stworzyłem obiekt listy przechowującej obiekty LocationDTO. W klasie wywoływana jest
metoda z warstwy prezentera getLocationListDTO, które jest żądaniem wywołania funkcji w
warstwie modelu odpowiedzialnej za pobranie wszystkich lokalizacji. Następnie wymagane
było uzupełnienie ciała metody populateControls, w której dodawane do widoku listy były
pobrane lokalizacje. Rysunek 4.29 przedstawia metodę populateControls.
Rys. 4.29 Metoda populateControls z klasy AddNewEmployeeScreen
Po wprowadzeniu powyższych modyfikacji musiałem jeszcze zadbać o odpowiednie pobranie
wartości z wypełnionego formularza. Jedną ze zmian była podmiana kodu do sczytania
wartości lokalizacji (rysunek 4.30 przedstawia kod przed modyfikacją, natomiast na rysunku
4.31 jest kod obsługujący pobranie z listy). Co więcej w polach formularza dla numeru domu
i mieszkania w przypadku wpisania tekstu generowany był wyjątek NumberFormatException,
więc linię kodu do pobrania wartości z pola objąłem klauzulą try-catch.
Rys. 4.30 Kod korzystający z pola tekstowego do pobrania wartości
Rys. 4.31 Kod korzystający z wyboru elementu z listy
W oknie do tworzenia rezerwacji dobudowane są dwie listy – pracowników i zasobów, które
zawierają dane ograniczone do konkretnej lokalizacji. Są to listy z multiwyborem, więc
użytkownik może objąć kilku pracowników i zasobów jedną rezerwacją. Na rysunku 4.32
znajduje się linia kodu, która odpowiada za opcję multiwyboru.
39
Rys. 4.32 Ustawienie listy wielokrotnego wyboru
Zaznaczone elementy listy po wciśnięciu przycisku zatwierdzenia formularza są pobierane do
obiektu ArrayList. Aby nie iterować zawsze przez całą listę pobierany jest indeks
najmniejszego zaznaczonego elementu. W przypadku, gdy żaden z elementów listy nie jest
zaznaczony metoda zwraca wartość -1, więc przed mazaniem po pamięci zabezpiecza
dodatkowy warunek w pętli for i>=0. Na rysunku 4.33 znajduje się przykładowy kod
obsługujący pobranie zaznaczonych elementów na liście pracowników.
Rys. 4.33 Obsługa pobrania wielu zaznaczonych elementów
Klasa EmployeeDetailsFormScreen jest odpowiedzialna za budowę interfejsu użytkownika z
formularzem edycji danych pracownika. Zmianą jaką w niej dokonałem było ustawienie w
polach typu TextField wartości aktualnych danych edytowanego pracownika, gdyż po
wygenerowaniu kodu były one puste. Rysunek 4.34 przedstawia przykład dodawanej w tym
celu linii kodu.
Rys. 4.34 Ustawienie wartości w polu typu TextField
Klasy ekranów w których wyświetlane mają być szczegóły m.in. pracownika wymagały
oprócz poprawki takiej jak w przypadku edycji danych, to również musiałem zapewnić brak
możliwości edycji. Rysunek 4.35 przedstawia linię kodu odpowiedzialną za uniemożliwienie
edycji pola.
Rys. 4.35 Zablokowanie możliwości edycji pola typu TextField
Ostatnią modyfikacją było dodanie odpowiednich przycisków na ekranie głównym
pracownika i managera. Wiąże się ona tylko z tym, że w modelu dziedzinowym nie
stworzyłem relacji między odpowiednimi przyciskami, a wskazanymi ekranami.