Posts Tagged Java

Zarządzanie transakcjami przez serwer aplikacji

W środowiskach zarządzanych (czyli np w serwerze aplikacyjnym JBoss AS) to te systemu mogą zarządzać transakcjami, czyli rozpoczynać, kończyć je w odpowiednim momencie, zwalniając z tego obowiązku programistę. W aplikacji można zdefiniować, jak dany fragment kodu ma wpływać na transakcje. Jeżeli sposób zachowanie nie zostanie zdefiniowany przez metodę, to kontener rozpoczyna transakcję zanim rozpocznie się wykonywanie metody, i kończy ją tuż przed końcem jej wykonywania. Nie są dozwolone zagnieżdżone transakcje, każda metoda może zostać skojarzona z jedną transakcją.

Definicja rodzaju transakcji

Rodzaje transakcji można zdefiniować przy użyciu adnotacji TransactionAttribute oraz TransactionAttributeType.

Adnotacja TransactionAttribute może występować zarówno na poziomie deklaracji klasy jak i deklaracji metody. Jeżeli zostanie podana przy deklaracji klasy, oznacza to że dany poziom transakcji ma zostać użyty we wszystkich metodach danej klasy, w przypadku deklaracji na poziomie metody odnosi się tylko do niej. W przypadku gdy występuje w jednym jak i drugim miejscu, pod uwagę brana jest wartość występująca przy deklaracji metody.

Poniżej przykład deklarowania rodzajów transakcji, na poziomie klasy i metod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class UserManager {
   
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public String getUserName() {
        return null;
    }
   
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void setUserName(String name) {
       
    }
}

Typy transakcji

Za pomocą adnotacji TransactionAttributeType można zdefiniować rodzaj transakcji, jaka ma obowiązywać w metodach. Występują następujące typy transakcji:

  • MANDATORY
    Konieczność wykonania metody w ramach istniejącej już transakcji. Jeżeli dla danego klienta istnieje już działająca transakcji, dana metoda zostanie w jej ramach wykonana. Jeżeli natomiast taka transakcji nie istnieje, to zostanie wyrzucony wyjątek TransactionRequiredException. Należy użyć tego atrybutu używać wtedy, gdy dana metoda musi zostać wykonana w ramach transakcji klienta.
  • REQUIRED
    Jeżeli klient działa w ramach transakcji i zostanie wywołana metoda oznaczona tym typem, to zostanie ona wykonana w ramach tej transakcji. Jeżeli natomiast klient nie działa w ramach transakcji, to zostanie rozpoczęta nowa, zanim metoda zostanie uruchomiona. Jest to także domyślne zachowanie, jeżeli nie zostanie ustawiony typ transakcji.
  • REQUIRES_NEW
    Jeżeli klient nie działa w ramach transakcji, to po prostu jest rozpoczynana nowa przed uruchomieniem metody. Natomiast jeżeli jest istnieje już działająca transakcja, to podejmowane są następujące kroki:

    1. Zawieszenie aktualnie działającej transakcji.
    2. Rozpoczęcie nowej transakcji do wykonania wybranej metody.
    3. Wywołanie i wykonanie metody.
    4. Po zakończeniu działania metody ponowne uruchomienie wcześniej zawieszonej transakcji.

    Typu tego należy używać w sytuacji, gdy istnieje potrzeba wykonywania danej metody zawsze w nowej transakcji.

  • SUPPORTS
    Jeżeli klient działa w ramach transakcji i wywoła daną metodę, to zostanie ona wykonana w ramach tej transakcji. Jeżeli natomiast transakcja nie istnieje, to nie zostanie ona także rozpoczęta przed wykonaniem wybranej metody.
  • NOT_SUPPORTED
    Jeżeli klient działa w ramach transakcji, to zostanie ona zatrzymana na czas wywołania wybranej metody, a po jej wykonaniu ponownie przywrócona. Jeżeli nie ma takiej transakcji, metoda zostanie po prostu wykonana, bez rozpoczynania nowej.

    Należy używać tego typu wtedy, gdy wybrana metoda nie potrzebuje transakcji do działania, a zależy nam na większej wydajności jej wykonywania (transakcje mają negatywny wpływ na szybkość wykonywania metod).

  • NEVER
    Jeżeli klient działa w ramach transakcji i wywoła metodą oznaczoną tym typem, zostanie wyrzucony wyjątek RemoteException. Natomiast jeżeli transakcja nie istnieje, to metoda zostanie wykonana bez rozpoczynania nowej transakcji.

Mała tabela, która podsumowuje powyższe:

Zachowanie kontenera w zależności od typu i stanu transakcji
Nazwa atrybutu Transakcja istnieje Brak transakcji
MANDATORY używa istniejącej wyrzuca wyjątek
REQUIRED używa istniejącej rozpoczyna nową
REQUIRES_NEW zawiesza istniejącą, rozpoczyna nową rozpoczyna nową
SUPPORTS używa istniejącej działa bez
NOT_SUPPORTED zawiesza istniejącą działa bez
NEVER wyrzuca wyjątek działa bez

Źródła

Tags: , , , , ,

Model nawigacji w JSF

Model nawigacyjny JSF pozwala na zdefiniowanie nawigacji pomiędzy stronami oraz na wykonywania dodatkowych akcji związanych z przechodzeniem pomiędzy stronami. W terminologii JSF nawigacją jest nazywany zestaw reguł, za pomocą których można stwierdzić jaka następna strona ma zostać wyświetlona po wybraniu jakieś przycisku bądź linku znajdującego się na stronie. Reguły te są zdefiniowane w pliku konfiguracyjnym faces-config.xml.

Jak zdefiniować regułę nawigacyjną?

Zdefiniowanie prostej nawigacji pomiędzy stronami sprowadza się do:

  • zdefiniowaniu odpowiednich reguł w pliku konfiguracyjnym faces-config.xml
  • odwołanie się do poprzez zdefiniowany ciąg znaków z poziomu przycisku lub linku

Przykładowy zapis w pliku konfiguracyjnym:

<navigation-rule>
    <from-view-id>/login.jsp</from-view-id>
    <navigation-case>
        <from-outcome>sukces</from-outcome>
        <to-view-id>/home.jsp</to-view-id>
    </navigation-case>
    <navigation-case>
        <from-outcome>błąd</from-outcome>
        <to-view-id>/login.jsp</to-view-id>
    </navigation-case>
</navigation-rule>

Aby wykorzystać podany zapis, należy w następujący sposób zbudować link lub przycisk (w pliku login.jsp):

<h:commandButton id="submit" action="sukces"
        value="Submit" />

W pliku konfiguracyjnym faces-config.xml definiujemy zasady nawigacji. Czyli:

  • navigation-rule – definicja reguły nawigacyjnej
  • from-view-id – informacja, jakiej strony dotyczą reguły
  • navigation-case – definicje wszystkich reguł, jakie mają mieć zastosowanie dla danej strony
  • from-outcome – definicja ciągu znakowego, który będzie użyty do rozpoznania danego przypadku nawigacyjnego, czyli przekirowania na podaną stronę, ciąg ten musi się „znaleźć” w atrybucie action, podany albo bezpośrednio, lub też zwrócony przez jakąś metodę
  • to-view-id – na jaką stronę przekierować przeglądarkę

Natomiast w pliku login.jsp definiujemy odpowiedni interfejs użytkownika (klikalny, czyli przycisk bądź link). Tam w jako parametr dla atrybutu action wprowadzamy zdefiniowany ciąg znaków, lub też wywołujemy jakąś metodę, która zwróci dany ciąg znaków (zdefiniowany w pliku konfiguracyjnym), co umożliwi odpowiednie przekierowanie w zależności od akcji.

I tak:

<h:commandButton id="submit" action="#{loginManager.login}"
        value="Submit" />

Metoda login zwraca ciąg znaków sukces w przypadku powodzenia podczas logowania. Nastąpi wtedy wykonanie reguły nawigacyjnej tak oznaczonej, i przekierowanie do strony ]home.jsp. Natomiast jeżeli uwierzytelnienie użytkownika nie powiedzie się, metoda ta zwraca ciąg znaków błąd, co spowoduje przekierowanie z powrotem do strony logowania.

Można także zdefiniować globalne przekierowania na daną stronę:

<navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
        <from-outcome>loguj</from-outcome>
        <to-view-id>/login.jsp</to-view-id>
    </navigation-case>
</navigation-rule>

Czyli niezależnie na jakiej stronie zostanie użyty w ciąg znaków loguj w atrybucie action, to zawsze nastąpi przekierowanie na stronę logowania.

Co się dzieje po wybraniu linka w przeglądarce?

W momencie, gdy użytkownik kliknie na przycisk lub też link, dany komponent generuje odpowiednie zdarzenie, którym informuje o tym fakcie. Zdarzenie to jest obsługiwane domyślną implementację interfejsu ActionListener, który wywołuje odpowiednią metodę z akcją zdefiniowaną w komponencie. Podana metoda wykonuje się i zwraca ciąg znaków, który zostanie użyty do podjęcia decyzji o nawigacji.

Zwrócony ciąg znaków jest przekazywany do domyślnej implementacji NavigationHandler, która bazując na tej wartości sprawdza, jaka strona powinna zostać wyświetlona.

Jeżeli uda się odnaleźć odpowiednią regułę nawigacyjną, rozpocznie się faza tworzenia docelowej strony HTML.

Źródła

Tags: , , , ,

Zakres działania ziaren zarządzanych przez JSF

W JSF ziarno zarządzane (managed bean) może mieć jeden z czterech zakresów:

  • application
    Obiekt o takim czasie życia funkcjonuje przez cały okres życia aplikacji, czyli jest tworzony w momencie uruchamiania aplikacji i niszczony w momencie zatrzymywania jej działania.
  • session
    Ziarna oznaczone w ten sposób mają czas życie ograniczony do długości trwania sesji. Czyli są tworzone w momencie tworzenia sesji i niszczone razem z jej zakończeniem. Sesja może zostać zniszczona: ręcznie przez aplikację lub też jej czas życia się skończył. Dlatego też dany obiekt może brać udział w wielu zapytaniach wysyłanych do serwera (np. przechowywać stan koszyka w sklepie internetowych).
  • request
    Czas życia ziarna jest ograniczony do pojedynczego zapytania, czyli od momentu rozpoczęcia przetwarzania żądania wyświetlenia strony do momentu jej całkowitego utworzenia. Po wysłaniu strony do klienta obiekt jest niszczony.
  • none
    Brak zakresu działania, używany czasem w dla ziaren zarządzających innymi obiektami.

Przykładowa definicji ziarna w pliku faces-config.xml:

<managed-bean>
    <managed-bean-name>customer</managed-bean-name>
    <managed-bean-class>
        com.mycompany.mybeans.CustomerBean
    </managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
        <property-name>mailingAddress</property-name>
        <value>#{addressBean.mail}</value>
    </managed-property>
    <managed-property>
        <property-name>streetAddress</property-name>
        <value>#{addressBean.street}</value>
    </managed-property>
    <managed-property>
        <property-name>customerType</property-name>
        <value>New</value>
    </managed-property>
</managed-bean>

Powyższy przykład pokazuje w jaki sposób zdefiniować zarządzalne ziarno oraz jak je zainicjalizować początkowymi wartościami.

Tags: , , , , , , , ,

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: , , ,