10 lutego 2007

requiredMessage i resource-bundle - udoskonalona kontrola komunikatów w JSF 1.2

Co nie dotknę, to coś nowego. Po prostu strach cokolwiek dotykać! ;-)

Po przeczytaniu sekcji 3.5 Encyjni obserwatorzy i metody przechwytujące specyfikacji JPA postanowiłem przygotować aplikację internetową, która pomogłaby mi utrwalić przeczytany materiał. Skorzystałem z pomocy NetBeans IDE 5.5.1 i GlassFish v2.

Rozpocząłem od stworzenia projektu i zabrałem się za tworzenie stron JSF. Pierwsza strona umożliwiała podanie nazwy użytkownika w polu h:inputText. Poszło gładko. Zdefiniowałem komponent zarządzany user, który miał przechowywać informację o wprowadzonym identyfikatorze użytkownika. Nie korzystałem z NetBeans Visual Web Pack 5.5, więc wszystko robiłem ręcznie, aż w pewnym momencie, edytując stworzony faces-config.xml dostrzegłem, że jestem w JSF 1.2 (!) Pomyślałem, że jest to dobra pora, aby zapoznać się z kilkoma dobrodziejstwami JSF 1.2, co zaraz przerodziło się w wykorzystanie gdzie się dało Unified EL, tj. tam, gdzie w poprzedniej wersji należało skorzystać z h:outputText teraz można zastąpić prostszymi konstrukcjami znanymi z JSP i JSTL, czyli ${nazwaKomponentuZarządzanego.atrybut}. Kiedy przyszło do przypisania komponentu zarządzanego user do h:inputText zauważyłem atrybut, którego z pewnością nie było w poprzedniej wersji JSF 1.1 - requiredMessage.

Zmiana komunikatów w JSF 1.1 związanych z obsługą błędów kontroli poprawności wprowadzonych danych nie była ani łatwa, ani zaawansowana (aż trudno uwierzyć, że twórcom JSF udało się to połączyć, zazwyczaj jest albo jedno, albo drugie). Zmiana komunikatów błędów polegała na dostarczeniu pliku komunikatów z odpowiednimi identyfikatorami, których wartości były zmodyfikowanymi komunikatami (w tym i tłumaczeniami). Bardziej zaawansowane modyfikacje komunikatów błędów wymagały zastosowania pewnych sztuczek (więcej w artykule Hansa Bergstena Designing and Implementing Web Application Interfaces).

W JSF 1.2 udostępniono atrybut requiredMessage. Wartość atrybutu requiredMessage jest komunikatem błędu, który będzie wyświetlany w przypadku niepodania przez użytkownika obowiązkowej wartości w polu typu UIInput (wymaganie nałożone przez zastosowanie atrybutu required dla kontrolek h:inputText, h:inputSecret, h:inputHidden i h:inputTextArea), bądź identyfikatorem komunikatu w aplikacyjnym pliku komunikatów. Komunikat (egzemplarz klasy FacesMessage) będzie umieszczony w FacesContext zamiast domyślnego.

<h:inputText id="name" value="#{user.name}" required="true" requiredMessage="Nie podano nazwy użytkownika" />

W powyższym przykładzie, jeśli użytkownik nie poda nazwy użytkownika wyświetlony zostanie komunikat Nie podano nazwy użytkownika (oczywiście samo wyświetlenie można zrealizować z pomocą h:message albo h:messages).

Na uwagę zasługuje jednak inna cecha requiredMessage - możliwość wskazania na właściwy komunikat w pliku komunikatów.

<h:inputText id="name" value="#{user.name}" required="true" requiredMessage="#{validationMessages.usernameMissing}" />

W ten sposób, w zależności od aktywnego ustawienia regionalnego (ang. locale), wyświetlony zostanie właściwy komunikat błędu w aktywnym języku. Ale co to jest validationMessages?

Poniżej znajduje się wycinek pliku konfiguracyjnego JSF - faces-config.xml:

<application>
<resource-bundle>
<base-name>pl.jaceklaskowski.ewt.faces.ValidationMessages</base-name>
<var>validationMessages</var>
</resource-bundle>
</application>
Zmienna validationMessages reprezentuje mapę komunikatów (z kluczami będącymi identyfikatorami komunikatów), a pl.jaceklaskowski.ewt.faces.ValidationMessages jest nazwą pliku komunikatów bez rozszerzenia .properties (w formacie java.util.Properties) o zawartości:

usernameMissing=Nie podano nazwy użytkownika!

Specyfikacja JSF 1.2 opisuje atrybut jako współpracujący z f:loadBundle, jednakże nie udało mi się tego powiązać. W dodatku znalazłem wiadomość na forum JavaServer Faces, która wskazywałaby, że taka możliwość nie ma prawa działać - requiredMessage and EL?.

Poza tym podobną funkcjonalność można wykorzystać do komunikatów związanych z mechanizmem konwersji i kontroli poprawności (walidacji) za pomocą atrybutów converterMessage oraz validatorMessage, odpowiednio.

Dobre wprowadzenie do zmian w JSF 1.2 znajduje się w artykule Web Tier to Go With Java EE 5: Summary of New Features in JavaServer Faces 1.2 Technology. Na lekturę specyfikacji JSF 1.2 przyjdzie jeszcze pora ;-)