Archive for category Java

Cykl życia strony JSF

W najprostszej formie cykl życia strony JSF nie rożni się od wywołania zwykłej strony JSP: klient wysyła żądanie pobrania wybranej strony a serwer generuje stroną poprzez wywołanie odpowiedniego serwletu. Jednakże model działania stron JSF jest bardziej skomplikowany, wymaga on aby komponenty były odpowiednio sprawdzane, pozwala na przechwycenie odpowiednich zdarzeń, pozwala na przesyłanie danych i tak dalej.

Poniższy rysunek (z dokumentacji The JEE 5 Tutorial, The Life Cycle of a JavaServer Faces Page) prezentuje poszczególne elementy cyklu życia aplikacji:

Standardowy cykl życia strony JSF

Standardowy cykl życia strony JSF

Powyższy diagram zawiera opis dwóch typów zapytań: żądanie początkowe oraz żądanie wyświetlenie ponowne. Żądanie początkowe występuje wtedy, gdy użytkownik wyświetla daną stronę po raz pierwszy, natomiast z wyświetleniem ponownym do czynienia mamy w momencie np. przesłania formularza, który był wcześniej wczytany w fazie pierwszej. Jeżeli następuje żądanie początkowe, to wykonywane są tylko kroki związane z przywróceniem widoku oraz wygenerowaniem odpowiedzi, ponieważ nie ma żadnych danych do przetworzenia. Natomiast z drugim przypadku cykl życia obejmuje wszystkie fazy.

Jeżeli żądanie wyświetlania strony JSF pochodzi z kliknięci ana linka o zwykle jest początkowe żądanie wyświetlenia strony. W takim przypadku zostaje utworzony nowy widok i zapisany w instancji klasy FacesConfig. Aplikacja następnie pobiera obiekty niezbędne do wyświetlenia widoku i wywołuje metodę FacesContext.renderResponse, która powoduje natychmiastowe utworzenie strony z pominięcie Render Response Phase. Operacja ta jest widoczna na diagramie pod nazwą Render Response.

Istnieje czasem potrzeba przekierowanie strony w jakiejś inne miejsce (dostęp do jakiegoś pliku, usługi) lub też strona nie zawiera żadnych komponentów JSF. W takiej sytuacji należy pominąć krok Render Response Phase poprzez wywołanie metody FacesContext.responseComplete. Sytuacja taka znajduje się na diagramie oznaczona nazwą Response Complete.

Restore View Phase

Pierwszą fazą w cyklu życia strony JSF jest Restoe View Phase. Jest ona wywoływana po tym, jak serwer zostanie poproszony o wyświetlenie strony po wybraniu np. jakieś linka. Podczas tej fazy biblioteka JSF tworzy widok, wiąże odpowiednie uchwyty zdarzeń oraz walidatory z odpowiednimi komponentami na widoku, oraz zapisu tak przygotowaną stronę w swojej pamięci podręcznej.

Jeżeli jest to żądanie początkowe zostaje zvudowany pusty widok i następuje przejście do kroku Render Response Phase, gdzie pusty widok jest wypełniany odpowiednimi komponentami znajdującymi się na stronie (czyli następuje utworzenie strony HTML)

Jeżeli natomiast mamy do czynienie z żądaniem ponownym, to widok odpowiadający danej stronie już istnieje w pamięci JSF. Następuje wtedy jego przywrócenie przy użyciu informacji o stanie zapisanych po stronie klienta lub serwera i przejście do następnego kroku.

Apply Request Values Phase

Po odczytaniu struktury komponentu z pamięci podręcznej JSF w pamięci jest już utworzone drzewo komponentów i teraz każdy z nich odczytuje nowe parametry czy też wartości z parametrów przekazanych w zapytaniu o stronie. Odczytana wartość zostaje lokalnie zapisane w danym komponencie. Jeżeli z jakiś powodów nie uda się poprawnie odczytać wartości, zostanie utworzony komunikat o błędzie skojarzony z odpowiednim komunikatem i wysłany do kolejki komunikatów FacesContext. Zostanie on potem wyświetlony już w trakcie tworzenia strony HTML, łącznie z innymi komunikatami które zostały czy też zostaną w kolejnych fazach utworzone.

Process Validations Phase

Podczas tego kroku następuje sprawdzenie poprawności danych zapisanych w poszczególnych komponentach. Sprawdzeniu zostają poddane odpowiednie atrybuty komponentów i są one testowane pod kątek zdefiniowanych reguł oraz ograniczeń.

Jeżeli wystąpi błąd podczas testów, zostaje wygenerowany komunikat błędu i dodany do kolejki komunikatów w FacesContext. W takim przypadku następuje także przejście do fazy odpowiedzialnej za utworzenie strony HTML (Render Response Phase), gdzie nastąpi wyświetlenie wszystkich komunikatów o błędach.

Trzy uwagi:

  • jeżeli jakakolwiek metoda wywoływana podczas tej fazy wywoła metodę FacesConext.renderResponse nastąpi przejście do kroku tworzenia strony HTML (Render Response Phase)
  • jeżeli aplikacje chce przekierować zapytań do innego zasobu (strony) lub też na stronie nie ma komponentów JSF, może wywołać metodę FacesContext.responseComplete
  • jeżeli jakieś zdarzenie zostaną zakolejkowane to JSF prześle je do nasłuchujących obiektów

Update Model Values Phase

Po sprawdzeniu, że dane są poprawne, JSP może zająć się ustawianiem odpowiednich wartości w obiektach znajdujących sie po stronie serwera. Zaktualizowane zostaną tyle te wartości, które zostały przesłane do aktualizacji w zapytaniu o stronę. Jeżeli wystąpią błędy podczas przypisywania wartości, to JSF przejdzie do kroku tworzenia strony HTML (Render Response Phase).

Trzy uwagi (jak wyżej):

  • jeżeli jakakolwiek metoda wywoływana podczas tej fazy wywoła metodę FacesConext.renderResponse nastąpi przejście do kroku tworzenia strony HTML (Render Response Phase)
  • jeżeli aplikacje chce przekierować zapytań do innego zasobu (strony) lub też na stronie nie ma komponentów JSF, może wywołać metodę FacesContext.responseComplete
  • jeżeli jakieś zdarzenie zostaną zakolejkowane to JSF prześle je do nasłuchujących obiektów

Invoke Application Phase

Podczas tego kroku JSF przetwarza wszelkiego rodzaju zdarzenia mające miejsce na poziomie aplikacji, takie jak wysłanie formularza czy też linkowania do innej strony.

Trzy uwagi (jak wyżej):

  • jeżeli jakakolwiek metoda wywoływana podczas tej fazy wywoła metodę FacesConext.renderResponse nastąpi przejście do kroku tworzenia strony HTML (Render Response Phase)
  • jeżeli aplikacje chce przekierować zapytań do innego zasobu (strony) lub też na stronie nie ma komponentów JSF, może wywołać metodę FacesContext.responseComplete
  • jeżeli jakieś zdarzenie zostaną zakolejkowane to JSF prześle je do nasłuchujących obiektów

Render Response Phase

Podczas tej fazy JSF generuje stronę przy użyciu JSP (jeżeli używamy JSP do generowania stron). W przypadku żądania początkowego komponenty znajdujące się na stronie zostaną dodane do drzewa komponentów jak tylko kontener JSP wykona stronę. Każdy komponent będzie samodzielnie tworzył odpowiedni kod HTML w monecie wywołania przez JSP.

W przypadku, gdy pojawią się jakieś błędy z poprzednich faz, zostanie wyświetlona oryginalna strona wraz z odpowiednimi komunikatami o błędach.

Po poprawnym utworzeniu strony jej stan zosanie zapisany, tak aby dało się go ponownie wykorzystać w razie potrzeby.

Źródła

Tags: , , , , ,

Czym jest JSF (JavaServer Faces)?

JavaServer Faces jest biblioteką przeznaczoną do budowania interfejsów użytkownika w aplikacjach WWW. Składa się ona z:

  • różnego zestawu API, na które składają się odpowiednie komponenty reprezentujące poszczególne elementu interfejsu użytkownika i pozwalające na zarządzanie ich stanem, przechwytywaniem zdarzeń, walidacji danych wejściowych, definicję nawigacji pomiędzy stronami, wpierające internacjonalizację;
  • zestawu komponentów JavaServer Pages (JSP) pozwalających na odwoływanie się do komponentów JSF na typowych stronach JSP

Powstanie JSF jest odpowiedzią na problemy, które istnieją podczas budowy stron tylko przy użyciu standardowych stron JSP, takich jak:

  • konieczność częstego powtarzania kodu
  • bezpośrednia praca z protokołem HTTP (pobieranie danych, wysyłanie strony do klienta)
  • konieczność ręcznej walidacji danych
  • brak wsparcie ze stron IDE
  • i pewnie wile innych, jak w każdej bibliotece niskopoziomowej

JSF miała się stać intuicyjną bibliotekę, która ułatwiła tworzenie aplikacji. A to dzięki:

  • umożliwienie prostego umieszczania wybranych komponentów na stronie WWW
  • powiązanie zdarzeń występujących po stronie użytkownika z odpowiednim kodem wykonywanym po stronie serwera
  • powiązanie komponentów graficznych ze strony z danymi znajdującymi się po stronie serwera
  • tworzenie interfejsu użytkownika poprzez komponenty, które mogą być łatwo rozszerzane i wykorzystywane w innych miejscach
  • zapisywanie i odzyskiwanie stanu interfejsu użytkownika ponad czas trwanie zwykłego zapytania do serwera

Czemu JSF

JSF zostało rozwinięte w ramach Java Community Process (JCP) w ramach JSR-252. Projekt zakładał, że z biliteki tej będa korzystali nie tylko programiście, ale także ludzie tacy jak:

  • twórcy stron WWW – są odpowiedzialni za tworzenie wyglądu strony, definiują go m.in. poprzez użycie odpowiednich, dostarczonych komponentów;
  • programiści aplikacji – integrują aplikacje z wygląd, tworzą obiekty, oprogramowują zdarzenia i inne operacje;
  • twórcy komponentów – tworzą komponentu graficzne, wykorzystując możliwości JSF pod względem rozszerzania oraz ponownego używania kodu;
  • architekci aplikacji – projektują aplikację, definiują nawigację pomiędzy stronami, zapewniają odpowiednią skalowalność aplikacji;
  • dostarczyciele narzędzi – tworzą odpowiednie narzędzia, które mają ułatwić korzystanie z technologii JSF (np, JBoss Tools).

JSF powstało wg wzorca projektowego Model-View-Controller (MVC). Dlatego też łatwiej się projektuje aplikacje przy użyciu JSF (w porównaniu ze zwykłymi stronami JSP) oraz są one prostsze (i tańsze) w późniejszym utrzymaniu. Zalety korzystania z JSF:

  • JSF to zbiór standardowych, wielokrotnie używalnych komponentów pozwalających na tworzenie interfejsu użytkownika
  • w JSF znajduje się wiele bibliotek tagów, które pozwalają na dostęp oraz modyfikację komponentów
  • pozwala na automatyczne zapisanie danych oraz ponowne ich wczytanie gdy są wyświetlane ponownie po stronie klienta
  • ukrywa przed programistami operacje przechwytywania zdarzeń oraz wyświetlania komponentów, pozwalając skoncentrować się po prostu na ich obsłudze
  • łatwe tworzenie własnych rozszerzeń i używanie ich łącznie ze standardowymi elementami JSF
  • możliwość łatwego tworzenia nawigacji pomiędzy różnymi stronami
  • wsparcie dla wielu różnych urządzeń występujących po stronie klienta (ważne, gdy tworzymy stronę mającą także działać poprawnie z telefonami komórkowymi)
  • wsparcie dla tłumaczenia zawartości strony

Źródła

Tags: , , ,

Poziom izolacji transakcji w JDBC

Dostępny interfejs dostępu do baz danych w Javie (JDBC) udostępnia kilka różnych poziomów izolacji poszczególnych transakcji. Pozwala na określenie, jak bardzo poszczególne transakcje mają być oddzielone od siebie. Niezależnie od poziomu izolacji transakcji, operacje takie jak wstawianie (INSERT), usuwanie (DELETE) oraz modyfikowanie (UPDATE) rekordów zachowują się zawsze tak samo, jedynie zachowanie operacji pobierającej (SELECT) dane z tabeli może być rożne.

Poziom transakcji jest ustawiany w ramach pojedynczego połączenia z bazą danych. Można go ustawia się go przy użyciu metody Connection.setTransactionIsolation(). Im wyższy poziom izolacji transakcji tym generalnie mniejsza wydajność operacji na bazie danych oraz większe prawdopodobieństwo wystąpienia blokad w dostępie do bazy danych.

Anomalie występujące w transakcjach

Poniżej znajduje się zestawienie anomalii, jakie mogą wystąpić w transakcjach:

Anomalie występujące w transakcjach
Nazwa anomalii Przykład działania anomalii
Dirty Reads

Mamy z nią do czynienia wtedy, gdy następuje w danej transakcji A odczyt zmodyfikowanych w transakcji B danych, a transakcja ta (B) nie została jeszcze zatwierdzona.

Transakcja A rozpoczyna się, i wywołuje:

SELECT * FROM zamowienia

Transakcja B w tym samym czasie wykonuje:

UPDATE zamowienie
SET wartosc_zamowienia=100
WHERE nr_zamowienia=123

Istnieje możliwość, że w transakcji A zostanie odczytana nowa wartość pola wartosc_zamowienia, nawet jeżeli nie zostanie to zapytanie zatwierdzone.

Non-Repeatable Reads

Ze zdarzeniem takim mamy do czynienia wtedy, gdy zapytania A wykonane w różnych momentach jednej transakcji może zwrócić inne wyniki (to samo zapytanie nie daje tego samego rezultatu). Zdarzyć się tak może, gdy w trakcie działania transakcji dane zostaną zmodyfikowane przez inną operacje na bazie danych.

Transakcja A rozpoczyna się, i wywołuje:

SELECT * FROM zamowienia
WHERE nr_zamowienia=123

Transakcja B w tym samym czasie wykonuje:

UPDATE zamowienie
SET wartosc_zamowienia=100
WHERE nr_zamowienia=123;

COMMIT;

Wykonanie ponowne zapytania w transakcji A spowoduje, że zostanie tym razem zwrócony zmodyfikowany rekord.

Phantom Reads

Z taką sytuacją mamy do czynienia wtedy, gdy transakcja A odczytuje dane z bazy danych, w trakcie jej trwanie transakcja B umieści w bazie danych rekord, który spełnia warunki zapytania z transakcji A. Jeżeli teraz w transakcji ponownie zostanie wykonane zapytanie, nowy rekord także zostanie zwrócony, co powoduje niezgodność wyniku działania dwóch zapytań w ramach tej samej transakcji.

Transakcja A odczytuje dane:

SELECT * FROM zamowienia
WHERE nr_zamowienia > 123

Transakcja B wstawia nowy wiersz do tabeli:

INSERT INTO zamowienia
(nr_zamowienia, nazwa)
VALUES ('140', 'Babol złapany');

COMMIT;

Jeżeli teraz w transakcji A ponownie wykonamy zapytanie, to nowy rekord także zostanie pobrany.

Poziomy transakcji

Rozróżniane są następujące poziomy transakcji:

  • TRANSACTION_READ_UNCOMMITTED

    Brak izolacji. Wszelkie zmiany, także te które nie są zatwierdzone jeszcze, są widoczne dla wszystkich zapytań w bazie danych.

  • TRANSACTION_READ_COMMITTED

    Minimalna izolacja, transakcje widzą tylko takie dane, które już są zatwierdzone i zapisane w bazie danych.

  • TRANSACTION_REPEATABLE_READ

    Poziom ten zapewnia powtarzalność odczytu danych. Jeżeli jakiś rekord zostanie odczytany, to nawet jego zatwierdzona modyfikacja w innej transakcji nie zmieni jego wartości przy ponownym odczycie.

  • TRANSACTION_SERIALIZABLE

    Najwyższy poziom transakcji, zwany szeregowym. Zapewnia on najlepszą izolację poszczególnych transakcji, które nie widzą swoich wzajemnych działań i nie wpływają na siebie. W momencie rozpoczęcia transakcji, stan bazy danych jest „zamrażany” i tylko na takim stanie transakcja może działać.

Lista anomalii jakie występują przy określonych typach transakcji, w zależności od sposobu blokowania danych:
Nazwa transakcji Blokada tabeli Blokada wiersza Wydajność
TRANSACTION_READ_UNCOMMITTED Możliwe: dirty reads, non-repeatable reads, phantom reads Możliwe: dirty reads, non-repeatable reads, phantom reads najszybsza
TRANSACTION_READ_COMMITTED Możliwe: non-repeatable reads i phantom reads Możliwe: non-repeatable reads i phantom reads szybka
TRANSACTION_REPEATABLE_READ Ponieważ blokowana jest cała tabela, to phantom reads nie są możliwe Możliwe są phantom reads średnia
TRANSACTION_SERIALIZABLE Brak anomalii Brak anomalii wolna

Źródła

Tags: , , , ,

Użycie słowa kluczowego break

Słowo kluczowe break może występować w dwóch formach:

  • forma samodzielna, bez etykiety
  • wskazanie etykiety, która ma zostać wywołania

Słowo kluczowe break bez etykiety

Samodzielne słowo break może zostać użyte tylko w kontekście pętli (for, while, do-while) oraz konstrukcji switch.

W przypadku pętli powoduje natychmiastowe przerwanie jej wykonywania i przejście do wykonywania nasŧpnej instrukcji po zakończeniu pętli. W przypadku wywołania polecenia wewnątrz wewnętrznej pętli, zostanie przerwane wykonywanie tylko pętli wewnętrznej.

1
2
3
4
5
6
7
8
9
10
11
12
for (int i = 0; i < 10; i++) {
    System.out.print("i = " + i);

    for (int j = i; j < i + 5; j++) {
        System.out.print("  j = " + j);
        if (j < 4) {
            break;
        }
    }

    System.out.println();
}

Użycie break w linii 7 w powyższym kodzie spowoduje przejście aplikacji do wykonywania kody w linii 11 (czyli ciągle wewnątrz pierwszej pętli).

Także break jest niezastąpione podczas używania konstrukcji switch:

1
2
3
4
5
6
7
8
9
10
11
12
13
int test = 1;

switch (test) {
default:
    System.out.println("Wartość domyślna");
case 0:
    System.out.println("Zero");
case 1:
    System.out.println("Jeden");
    break;
case 2:
    System.out.println("Dwa");
}

Co zostanie wydrukowane po uruchomieniu powyższego fragmentu kodu? Zaskoczenia żadnego nie będzie:

Jeden

Czyli zostanie wywołana linia 9, a następnie nastąpi opuszczenie całej konstrukcji switch.

Ale oto co zostanie wypisane na ekranie, jeżeli zmienimy przypisanie int test = 4:

Wartość domyślna
Zero
Jeden

Ponieważ wartość 4 nie ma żadnego przypadku opisanego w switch więc jest wykonywany blok wejścia default. I następnie kod jest wykonywany aż do pierwszego napotkanego słowa break lub też końca konstrukcji switch.

Słowo kluczowe break z etykietą

Istnieje także możliwość podania etykiety po słowie kluczowym break. Konstrukcja to może zostać użyta do zakończenia każdego bloku oznaczonego daną etykietą. Powoduje przejście wykonywania kodu do pierwszej instrukcji następującym po danym bloku kodu oznaczonym etykietą:

1
2
3
4
5
6
7
wyjscie: {
    int j =2;
    if (j == 2)
        break wyjscie;
    System.out.println("Blok danych z etykietą");
}
System.out.println("Koniec");

Po wykonaniu powyższego kodu zostanie wydrukowana tylko pojedyncza linia:

Koniec

Tę wersję konstrukcji break często używa się w połączeniu z zagnieżdżonymi pętlami, pozwala na opuszczenie całej ich struktury bez kłopotliwych testów na poszczególnych jej poziomach.

Tags: , , ,

Inicjalizacja zmiennych w pętli for

Definicja pętli for jest następująca:

for (<inicjalizacja>; <warunek pętli>; <wyrażanie zwiększające wartość>)
     <instrukcje do wykonania>

Chyba najczęściej używana forma instrukcji for wygląda tak:

1
2
3
4
5
6
for (int i = 0; i < 10; i++) {
        int k = 0;
        for (k = 0; k < i; k++) {
                // zrób coś
        }
}

Widać, że inicjalizacja zmiennej w pętli może zostać połączona także z jej deklaracją. Należy pamiętać, że jeżeli deklarację przeprowadzimy w części związanej z inicjalizacją, to zmienna taka będzie widziana tylko w ramach instrukcji for.

Nie trzeba ograniczać się do inicjalizacji tylko jednej zmiennej, można zrobić coś takiego:

1
2
3
for (int i = 0, k = 0; i < 3 && k < 1; i++, k++) {
        System.out.println("Pętla : i = " + i + ", k = " + k);
}

Kolejne inicjalizacje zmiennych powinny być rozdzielone przecinkami i wszystkie są tego samego typu. Nie jest dozwolona taka konstrukcja:

1
2
3
for (int i = 0, long k = 0; i < 3 && k < 1; i++, k++) {
    System.out.println("Pętla : i = " + i + ", k = " + k);
}

Można to ominąć, przenoszą deklarację zmienny poza pętlę for:

1
2
3
4
5
int i;
long k;
for (i = 0, k = 0; i < 3 && k < 1; i++, k++) {
    System.out.println("Pętla : i = " + i + ", k = " + k);
}

Jest także możliwa tak egzotyczna konstrukcja:

1
2
3
4
int i, k;
for (i = 0, k = 0, System.out.println("Petla for"); i < 3; i++) {
    System.out.println("Pętla : i = " + i + ", k = " + k);
}

Oczywiście, nie jest to zalecany sposób komunikowania, że rozpoczyna się pętla :).

Źródła

Tags: , , , ,