05 czerwca 2008

EJB 3.0 Redbook opublikowany i doświadczenia z trinidadowym tr:tree

Podczas mojego wystąpienia o Apache Wicket na konferencji JAVArsovia 2008 publiczność nie pozostała mi dłużna w kontekście dzielenia się wiedzą i w trakcie moich bojów z poprawianiem błędów w edytorze javowym w Eclipse padło z sali: "Skorzystaj z Ctrl+1!". Okazuje się, że człowiek zaoszczędziłby wiele czasu, gdyby zamiast zabawiać się z Ctrl+Spacja, czy podobnie skorzystał po prostu z pomocy Ctrl+1, którą Tomek N. opisał w korespondencji do mnie:

Ctrl+1 działa także gdy w kodzie nie ma błędów, jego semantyka brzmi wtedy "Zrób to, czego w tej chwili potrzebuję" ;-). Podobnie Ctrl+2.

Wiadomo, że najprostsze rzeczy najtrudniej znaleźć, ale jak pokazuje mój przypadek warto podejmować się wyzwań w postaci wystąpień publicznych, bo to, co wczoraj mogło być moją niewiedzą, jutro jest już innych, a ja cieszę się z darmowej wskazówki. Najważniejsze, aby nie ukrywać swojej niewiedzy licząc na pomoc publiczności. Kolejny raz przekonałem się, że było warto. Dzięki Tomek!

Kolejna fajna rzecz przytrafiła mi się wczoraj - opublikowano moją pracę dotyczącą EJB 3.0 w wykonaniu IBM WebSphere Application Server 6.1 - WebSphere Application Server Version 6.1 Feature Pack for EJB 3.0. Wielu pamięta moje relacje z pobytu w US i teraz mogę już upublicznić cel mojej podróży - WebSphere Application Server Version 6.1 Feature Pack for EJB 3.0 aka EJB 3.0 Redbook, czyli pierwsza książka mojego autorstwa. Nie było lekko, ale bardzo przyjemnie, więc nie odczułem wielkiego zmęczenia. Współtworzyłem ją w iście międzynarodowym gronie: Ueli Wahli (Szwajcar), Giuseppe Bottura (Włoch) i Nidhi Singh (Hinduska) w słonecznej Kalifornii. Wiele dobrej zabawy i odpoczynku, co wierzę, że udało się zawrzeć w książce, której lekturę gorąco polecam. Proszę o krytyczne spojrzenie na pracę, której celem ma być przybliżenie EJB 3.0 i jego (jej?) realizacja przez WAS 6.1. Nie byłbym sobą, gdybym w takim momencie nie wspomniał również o nadchodzącym IBM WebSphere Application Server Network Deployment 7.0 Open Beta (WAS7), który dostępny jest w wersji beta na stronie IBM WebSphere software early programs - IBM WebSphere Application Server Network Deployment V7.0 Open Beta. Wspomniałem o nim przy okazji mojego wyjazdu do Sosnowca (IBM WAS 7.0 Open Beta oraz IBM RAD 7.5 Open Beta na moim wykładzie na Uniwersytecie Śląskim w Sosnowcu), gdzie zostałem tłumnie przywitany...w przeważającej większości całkowicie nieprogramującą społeczność (!) Ostatnie przewidywania o potencjalnej dacie pojawienia się wersji produkcyjnej JBoss AS 5.0 nie są imponujące, a tu proszę inni nadrabiają technologiczne straty i zaczynają stanowić wartościową alternatywę (gra słów zamierzona ;-)).

Wczoraj, na Wydziale MIMUW na Banacha 2 miało miejsce spotkanie z panem Andrzejem Blikle - właścicielem firmy cukierniczej A.Blikle i...informatykiem (o specjalności matematyczne podstawy informatyki), profesorem doktorem habilitowanym, członekiem Rady Języka Polskiego i Fundacji Kultury, od 1977 pracownikiem Instytutu Podstaw Informatyki Polskiej Akademii Nauk (za Andrzej Blikle w polskiej Wikipedii). Co za zbieg okoliczności, że można zajmować się i słodyczami, i informatyką (!) Ciekaw jestem ilu z Was wiedziało o matematycznych powiązaniach pana Blikle?! Co mnie najbardziej zaskoczyło podczas spotkania to fakt, że p. Blikle prowadzi comiesięczne i bezpłatne spotkania dotyczące TQM. Dzisiaj, czwartek 5.06.2008, odbędzie się kolejne spotkanie, ale niestety nie wiem gdzie i o której. Warto było wysłuchać prezentacji p. Blikle, na której wspominał o kilku zasadach prowadzenia firmy, których trudno by szukać w wielu - Zasada stałego dokonalenia - Aby doskonałe było to, co klient u nas kupuje, doskonalić musimy wszystko, wszyscy i stale) czy Nie oczekuj perfekcji, oczekuj postępu (za W.E.Demingiem). Takie sympatyczne spotkanie, które prowokuje do myślenia o naszej roli w firmie i sposobie prowadzenia własnej karierze zawodowej.

Wstęp mógł być trochę nużący, więc w myśl "Zasady stałego dokonalenia" czy "Nie oczekuj perfekcji, oczekuj postępu" najwyższa pora zabrać się za popróbowanie się z czymś nowym. Dzisiaj zajmę się Apache Myfaces Trinidad - zbiorem kontrolek i innych dodatków usprawniających aplikacje korzystające z JavaServer Faces, a dokładniej jednej kontrolce Trinidada - tr:tree. Do ostatniego projektu potrzebowałem skorzystać z kontrolki, która modelowałaby strukturę drzewiastą podobną do listy katalogów i zawartych w nich plikach. Idealnym kandydatem była właśnie kontrolka tr:tree. Jedyne co udało mi się do tej pory rozpoznać to zasilenie kontrolki moimi danymi w postaci javax.faces.model.DataModel (dokładniej org.apache.myfaces.trinidad.model.ChildPropertyTreeModel). O modelach zasilających struktury typu h:dataTable czy wspominany tr:tree pisałem w Tabele w JavaServer Faces - znacznik <h:dataTable>.

Tworzę projekt przy pomocy archetypu myfaces-archetype-trinidad (więcej w artykule Deklaratywne bezpieczeństwo w JSF z JAAS i Jetty czy notce Tworzenie projektu aplikacji JSF z pomocą myfaces-archetype-trinidad).

$ mvn archetype:generate -DarchetypeCatalog=http://myfaces.apache.org \
-DgroupId=pl.jaceklaskowski.faces.trinidad -DartifactId=myfaces-trinidad-tree -Dversion=1.0
(wybieram pozycję 5 i wciskam Enter zapytany przy Y:).

Utworzony projekt pracuje z Javą 1.4, więc zmieniam konfigurację projektu na Javę 5 dodając konfigurację wtyczki maven-compiler-plugin do pom.xml:
 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
UWAGA: Import projektu do Eclipse z pomocą wtyczki m2clipse kończy się utworzeniem projektu na poziomie Java 1.4, więc mimo powyższej zmiany mogą pojawić się problemy z kompilacją projektu. Należy zmienić konfigurację projektu w Properties > Java Compiler i odznaczyć Enable project specific settings (zakładając, że domyślnie Eclipse pracuje z Java 5 lub wyżej).

Następnie tworzę klasę modelu pl.jaceklaskowski.faces.trinidad.model.Category:
 package pl.jaceklaskowski.faces.trinidad.model;

import java.util.ArrayList;
import java.util.List;

public class Category {
private long id;
private String name;
private String description;
private Category parent;
private List<Category> children = new ArrayList<Category>();

public Category() {
}

public Category(String name) {
this.name = name;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Category getParent() {
return parent;
}

public void setParent(Category parent) {
this.parent = parent;
}

public List<Category> getChildren() {
return children;
}

public void setChildren(List<Category> children) {
this.children = children;
}

public void addCategory(Category category) {
this.children.add(category);
}

}
oraz ziarno zarządzane categoryAgent reprezentowane przez klasę pl.jaceklaskowski.faces.trinidad.CategoryAgent.
 package pl.jaceklaskowski.faces.trinidad;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.DataModel;

import org.apache.myfaces.trinidad.model.ChildPropertyTreeModel;

import pl.jaceklaskowski.faces.trinidad.model.Category;

public class CategoryAgent {
private long categoryId;
private Category category;
private List<Category> categories = new ArrayList<Category>();
{
Category root = new Category("Korzen");
root.addCategory(new Category("Podkategoria #1"));
root.addCategory(new Category("Podkategoria #2"));
root.addCategory(new Category("Podkategoria #3"));

categories.add(root);
}
private DataModel model = new ChildPropertyTreeModel(categories, "children");

public long getCategoryId() {
return categoryId;
}

public void setCategoryId(long categoryId) {
this.categoryId = categoryId;
}

public Category getCategory() {
return category;
}

public void setCategory(Category category) {
this.category = category;
}

public String selectCategory() {
Category selectedCategory = (Category) model.getRowData();
System.out.println("++ Wybrano kategorie o name: " + selectedCategory.getName());
return null;
}

public DataModel getModel() {
return model;
}

public void setModel(DataModel model) {
this.model = model;
}

}
Konfiguracja ziarna categoryAgent w faces-config.xml ("serce" aplikacji facesowej) wygląda następująco:
 <managed-bean>
<managed-bean-name>categoryAgent</managed-bean-name>
<managed-bean-class>pl.jaceklaskowski.faces.trinidad.CategoryAgent</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Zmieniam stronę index.jspx na poniższą, gdzie skorzystam z tr:tree do wyświetlenia dostępnych kategorii i ich powiązań.
 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:tr="http://myfaces.apache.org/trinidad">
<jsp:directive.page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" />
<f:view>
<tr:document title="Apache MyFaces Trinidad Archetype Demo">
<tr:form>
<tr:tree var="node" value="#{categoryAgent.model}">
<f:facet name="nodeStamp">
<tr:commandLink text="#{node.name}" action="#{categoryAgent.selectCategory}" />
</f:facet>
</tr:tree>
</tr:form>
</tr:document>
</f:view>
</jsp:root>
Uwieńczeniem prac są testy - mvn clean jetty:run i otwieram stronę http://localhost:8080/myfaces-trinidad-tree/faces/index.jspx (nie potrafię wytłumaczyć dlaczego Jetty nie respektuje wpisu welcome-file-list w desktyptorze wdrożenia aplikacji webowej, w której jawnie wskazano faces/index.jspx jako jedną z nich i stąd należy wpisać pełną ścieżkę do index.jspx!). Wciśnięcie plusa rozwija węzeł kategorii, natomiast minusa zwija. Poza tym wybór kategorii przez wciśnięcie jej nazwy powoduje wykonanie akcji w aplikacji, która sprowadza się do wyświetlenia komunikatu na konsoli. Wszystko działa jak należy!

Pytanie konkursowe: Jaka klasa (abstrakcyjna) z JSF jest podstawą dla źródła danych kontrolek JSF - h:dataTable czy tr:tree?