sobota, 27 lutego 2010

Tworzenie własnych komponentów w Facelets

Tworzenie własnych komponentów w JSF (przynajmniej 1.2, z wersją 2.0 nie miałem się jeszcze okazji zapoznać) jest dość skomplikowane i wymaga poświęcenia trochę czasu. Trzeba utworzyć dwie klasy oraz deskryptor komponentu TLD, no i zarejestrować nowy komponent. W Facelets sprawa jest dużo prostsza i wymaga tylko utworzenia pliku .xhtml, w którym najzwyczajniej tworzymy komponent w HTMLu i rejestracji.
Stwórzmy przykładowy komponent o dość banalnym zadaniu: wyświetlanie pola tekstowego wraz z etykietą.
Czyli dla:
<cust:labeledInput value="#{myBean.name}" id="myInput" label="Podaj imię: " />
Ma się wygenerować:
<label for="myInput">Podaj imię: </label>
<input id="myInput" type="text" name="myInput" value="" />
Zacznijmy od pliku .xhtml tworząc to co normalnie byśmy pisali za każdym razem dla takich komponentów:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core">

 <ui:composition>
  <h:panelGroup>
   <h:outputLabel for="#{id}" value="#{label}"/>
   <h:inputText id="#{id}" value="#{value}" />
  </h:panelGroup>
 </ui:composition>
</html>
Jeśli przypisujemy do tagu atrybut np. label="napis" to w definicji komponentu odwołujemy się do jego wartości poprzez #{label}. Trzeba przyznać, że jest to dość wygodne.
Pozostało już tylko zarejestrować komponent. Należy najpierw utworzyć plik XML definiujący bibliotekę tagów. myTags.taglib.xml:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://wookasz.blogspot.com/tags</namespace>
 <tag>
  <tag-name>labeledInput</tag-name>
  <source>LabeledInput.xhtml</source>
 </tag>
</facelet-taglib>
I ten plik należy dopisać w konfiguracji web.xml:
<context-param>
 <param-name>facelets.LIBRARIES</param-name>
 <param-value>
  /WEB-INF/facelets/tags/myTags.taglib.xml;
 </param-value>
</context-param>
I to starczy. Przykład użycia:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:cust="http://wookasz.blogspot.com/tags">

 <ui:composition>
  <f:view>
   <h:form>
    <cust:labeledInput value="#{myBean.name}" 
     label="Podaj imię: " id="nameInput"/>
   </h:form>
  </f:view>
 </ui:composition>
</html>
Po drobnej modyfikacji pliku komponentu:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core">

 <ui:composition>
  <h:panelGroup>
   <h:outputLabel for="#{id}" value="#{label}"/>
   <h:inputText id="#{id}" value="#{value}">
    <ui:insert/>
   </h:inputText>
   <h:message for="#{id}" />
  </h:panelGroup>
 </ui:composition>
</html>
Można będzie wstawiać inne węzły w węzeł komponentu. Umieszczane one będą w miejsce <ui:insert/>. Dodałem jeszcze wyświetlanie komunikatów błedów od walidatora co umożliwia takie użycie:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:cust="http://wookasz.blogspot.com/tags">

 <ui:composition>
  <f:view>
   <h:form>
    <cust:labeledInput value="#{myBean.name}" 
     label="Podaj imię: " id="nameInput">
     <f:validateLength maximum="15" minimum="2"/>
    <cust:labeledInput>
   </h:form>
  </f:view>
 </ui:composition>
</html>
...i nie martwienie się oprócz etykiety także o komunikat walidacji.

czwartek, 25 lutego 2010

Uwierzytelnianie w Spring Security z użyciem haseł zakodowanych funkcją MD5

Kolejny wpis dotyczący Spring Security. Tym razem do skonfigurowania jest aplikacja która podczas logowania użytkownika korzysta z haseł zapisanych po wcześniejszym zakodowaniu ich algorytmem MD5. Oczywiście będzie to dość proste i szybkie w skonfigurowaniu:)

Praktycznie jedynym co musimy zrobić to trochę zmodyfikować kontekst bezpieczeństwa aplikacji pliku w XML. W pierwszej kolejności należy dodać ziarno które będzie odpowiadać za tworzenie skrótu z hasła, będzie nim obiekt Md5PasswordEncoder:
<beans:bean id="passwordEncoder" 
        class="org.springframework.security.providers.encoding.Md5PasswordEncoder"/>
Następnie to ziarno musi być przypisane do beana odpowiedzialnego za uwierzytelnianie:
<beans:bean id="daoAuthenticationProvider"
 class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
 ...
 <beans:property name="passwordEncoder" ref="passwordEncoder"/>
 <beans:property name="saltSource"><beans:null/></beans:property>
        ...
</beans:bean>
W tym przykładzie nie używana jest sól, która może wpłynąć na poprawę bezpieczeństwa skrótu. Jeśli ktoś chce zwiększyć bezpieczeństwo powinien z niej skorzystać.
Algorytm kodowania może być w bardzo prosty sposób zmieniony, poprzez zmianę klasy Md5PasswordEncoder na inną (MD5 nie jest już zbyt bezpieczny:). Jeśli chcielibyśmy użyć algorytmu SHA-1 wtedy klasa ShaPasswordEncoder będzie bardziej pomocna.

Warto używać tego samego algorytmu do autoryzacji jak i do kodowania hasła przy zapisie do bazy danych. W przypadku MD5 (bez soli) poniższa metoda wykonuje to zadanie używając bibliotek Springowych:
public String encodePassword(final String password) {
    final Md5PasswordEncoder encoder = new Md5PasswordEncoder();
    // drugi parametr to źródło 'soli'
    return encoder.encodePassword(password, null);
}
Dla osób nie znających jeszcze Spring Security ponownie polecam wpis na blogu Mateusza Zięby -> Bezpieczeństwo szybko, łatwo i przyjemnie czyli wstęp do Spring Security :)

niedziela, 21 lutego 2010

Spotkanie Poznań JUG - Clojure

Teraz o czymś bliższym terminowo niż GeeCON :) W najbliższy wtorek odbędzie się spotkanie Poznańskiej Grupy Użytkowników Javy dotyczące programowania funkcyjnego oraz języka Clojure.
Pozwolę sobie wkleić streszczenie prelegenta Filipa Koczorowskiego:
Jeśli jeszcze nie wiecie, to przestała rosnąć prędkość działania procesorów. W zamian producenci oferują nam ich coraz większą liczbę. Aby móc jednak skorzystać z tego prezentu, musimy przestawić się na aplikacje wielowątkowe i współbieżne. Programowanie wielowątkowe jest bardzo trudne, więc jak to zrobić? Niektórzy twierdzą, że znaleźli odpowiedź i że nazywa się ona programowanie funkcyjne.
Termin oraz namiary:
Siedziba Cognifide - Aleje Wielkopolskie 4, Poznań
Wtorek 23.02.2010
Godzina 18:00

Zapraszam!!

Rejestracja na GeeCON 2010 otwarta !

Od 4 dni można już zacząć rejestrować się na drugą edycję konferencji GeeCON! W roku poprzednim odbyła się ona w Krakowie, w tym stolicą Javowego świata będzie Poznań! Cała impreza odbędzie się w dniach 12-14 maja i już zapraszam do zapisania się, ponieważ im później - tym drożej ;-)
Przewidziano 3 okresy rejestracji, w pierwszym ceny biletów są następujące:
399 PLN (105 EUR) - bilet normalny
299 PLN (80 EUR) - bilet studencki

Pierwszy okres kończy się 15 marca.
Oprócz możliwości wysłuchania prezentacji osób z całego świata, firma Adobe (złoty sponsor GeeCON) funduje także dla uczestników licencje na Adobe Flex Builder (dla zastosowań niekomercyjnych).

Chciałem jeszcze przypomnieć, że za tydzień kończy się Call for Papers. Więc jeśli masz coś ciekawego do powiedzenia i chcesz się tym podzielić z resztą świata to zachęcam do szybkiego zgłoszenia swojej propozycji! Call for Papers kończy się 28 lutego.

Więcej szczegółów o rejestracji tutaj, a o Call for Papers tutaj. Zapraszam też do przyłączenia się do grupy GeeCON Planet na Facebooku!

Do zobaczenia na GeeCONie !!

niedziela, 7 lutego 2010

Co nowego w Java 7 ? Część trzecia - będą domknięcia !

Wiadomość może nie jest najświeższa, niestety nie miałem ostatnio czasu aby czytać o rozwoju JDK 7, ale 10 grudnia ubiegłego roku ogłoszono akceptację projektu Lambda, czyli wprowadzanie domknięć w Javie! Udało się przepchnąć je do JDK 7 z powodu przesunięcia wydania finalnej wersji na wrzesień 2010, poza tym i tak pojawiłyby się w wersji 8.
Co nam dadzą domknięcia ? Dużo uproszczeń, kilka przykładów:

Typy funkcyjne:
#int(int, int) mnoz = #(int x, int y)(x*y);
int a = mnoz(10,20);
Funkcje też można zwracać:
#int(int, int) mnoz = #(){ return #(int a, int b)(a*b)};
int a = mnoz(10,20);
Definicja komparatora:
List<Person> list = ...
Collections.sort(list, #(Person a, Person b)( a.getAge() - b.getAge() ));
I najważniejsza funkcjonalność - extension methods:
// Załóżmy, że mamy metodę w klasie Collections:
class Collections {
  ...
  static <T> Set<T> filter(Set<T> s, #boolean(T) pred) { ... }
  ...
}
// interfejs dla zbioru:
interface Set<T> extends Collection<T> {
  ...
  Set<T> filter(#boolean(T)) import static Collections.filter;
  ...
}
// dzięki temu będziemy mogli wykonać filtrowanie w taki sposób:
Set<Integer> newSet = set.filter(#(int x)(x > 0));
// nowy zbiór będzie zawierać tylko wartości większe od zera
Polecam zapoznać się ze stroną Project Lambda: Straw-Man Proposal w poszukiwaniu większej liczby przykładów oraz stroną Closures for Java (v0.6a) gdzie opisano całą propozycję rozszerzenia.
Można też przeczytać: Closures for Java: The Q&A.

sobota, 6 lutego 2010

Tagi Spring Security i Facelets

Ostatni projekt przy którym pracowałem zmusił mnie do ponownego spotkania ze Spring Security. Wcześniej pracowałem z tym świetnym frameworkiem przy okazji pisania pracy inżynierskiej. Wtedy nie miałem praktycznie żadnych problemów z osadzeniem go w projekcie i podpięciem wszystkich funkcji (wielka chwała Mateuszowi Zięba za wpis na jego blogu - Bezpieczeństwo szybko, łatwo i przyjemnie czyli wstęp do Spring Security - polecam!). Tym razem Spring trochę mnie nie słuchał :)
Pojawił się problem całkowitego ignorowania tagów spring security w kodzie szablonu, silnik renderujący po prostu wyrzucał je do wynikowego HTMLa. Nie mogąc znaleźć na to rozwiązania spytałem grupę dyskusyjną o pomoc w sprawie, gdzie otrzymałem sugestie, że być może tagi springowe nie są kompatybilne z Facelets który był używany w projekcie. Okazało się to strzałem w dziesiątkę! Wersja Spring Security z którą wtedy pracowałem to 2.0.5 i wtedy (nie wiem jak jest z ver. 3.0 ? Ktoś wie ?) nie było tagów zgodnych z Facelets :-/
Z pomocą przyszedł wujek Google i projekt Spring Security Facelets Tag Library. Jest to autorskie rozwiązanie, ale gdzieś przeczytałem, że trwają rozmowy nad integracją ze Springiem.
Projekt jest bardzo ciekawy ponieważ rozwijane są wersje zgodne z JSF 1.2 jak i 2.0 oraz Spring Security 2.0 jak i 3.0.
No ale wracając to konkretów, biblioteka definiuje własne tagi działające z Facelets. Ich nazwy trochę odbiegają od tych w Springu ale możliwości są te same. Aby ich użyć w szablonie należy dodać namespace: http://www.springframework.org/security/facelets/tags
Drobne przykłady:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core" 
      xmlns:security="http://www.springframework.org/security/facelets/tags">
<ui:composition>
 <f:view>
  <security:ifNotGranted roles="ROLE_ADMIN">
     <h:outputText value="Użytkownik nie ma uprawnienia ROLE_ADMIN" />
  </security:ifNotGranted>
  <security:ifAnyGranted roles="ROLE_USER, ROLE_ADMIN">
     <h:outputText value="Użytkownik posiada chociaż jedno z uprawnień, ROLE_USER lub ROLE_ADMIN" />
  </security:ifAnyGranted>
  <security:ifAllGranted roles="ROLE_BOSS, ROLE_ADMIN">
     <h:outputText value="Użytkownik posiada oba uprawnienia, ROLE_BOSS oraz ROLE_ADMIN" />
  </security:ifAllGranted>
 </f:view>
</ui:composition>
</html> 
I wszystko ładnie śmiga :)