10 lipca 2007

Krótka przygoda z ICEFaces 1.6.0, Eclipse 3.3 i wtyczką Glassfish Eclipse Plugin

Do niedawna sądziłem, że wsparcie Eclipse IDE przy tworzeniu aplikacji Java EE jest...delikatnie mówiąc...słabsze niż w NetBeans IDE. Co rusz natrafiam jednakże na funkcjonalność Eclipse IDE, które zmienia moje zdanie nt. temat. Pojawiła się właśnie nowa wersja biblioteki ICEfaces 1.6.0 i postanowiłem sprawdzić, ile czasu zajmie mi uruchomienie prostej aplikacji internetowej z nią korzystając z Eclipse IDE 3.3 oraz wtyczki Glassfish.

Rozpoczynam od pobrania ICEfaces 1.6.0 ze strony ICEfaces Downloads.

Początkowo próbowałem namierzyć biblioteki w repozytorium m2, ale nie miałem szczęścia i odpuściłem. Później jeszcze raz próbowałem z wtyczką m2eclipse po zainstalowaniu ICEfaces w lokalnym repozytorium m2, ale w połączeniu z Eclipse i wtyczką Glassfish nie szło mi najlepiej i również odpuściłem.

Otwieram Eclipse IDE 3.3 z zainstalowaną wtyczką dla Glassfish (pracuję z Glassfish v2 b54).

Tworzę dynamiczny projekt aplikacji internetowej (New > Project > Web > Dynamic Web Project) o nazwie icefaces-witajswiecie. W międzyczasie definiuję Glassfish oraz wybieram JavaServer Faces Project Facet


i deklaruję korzystanie z biblioteki JSF przez zaznaczenie opcji Server Supplied JSF Implementation.

Kończę tworzenie projektu przyciskiem Finish.

Jako pierwszy krok dodaję biblioteki wymagane przez projekt ICEfaces opisane w dokumencie ICEfaces Library Dependencies.

Tworzenie strony JSF w Eclipse IDE to tworzenie strony JSP - New > JSP. Eclipse nie dostarcza dedykowanego pomocnika (wizard) dla stron JSF.

Pierwszą stronę nazwałem index.jsp, która będzie przekierowywała na stronę zawierającą elementy ICEfaces.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
<html>
<body>
<jsp:forward page="index.iface" />
</body>
</html>
A skąd to dziwne rozszerzenie - .iface? Jest to rozszerzenie, z którym domyślnie związuje się infrastrukturę JSF dostarczaną przez ICEfaces przez deklarację w deskryptorze aplikacji internetowej WEB-INF/web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>icefaces-witajswiecie</display-name>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.iface</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jspx</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.synchronousUpdate</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>com.icesoft.faces.concurrentDOMViews</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Persistent Faces Servlet</servlet-name>
<servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Blocking Servlet</servlet-name>
<servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>
<url-pattern>*.iface</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Persistent Faces Servlet</servlet-name>
<url-pattern>/xmlhttp/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Blocking Servlet</servlet-name>
<url-pattern>/block/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
</web-app>
W deskryptorze aplikacji internetowej zauważyć można definicję kilku dodatkowych servletów, które uaktywniają ICEfaces. ICEfaces jest rozszerzeniem dla JSF (siłą JSF jest właśnie mechanizm umożliwiający jego rozbudowę z czego skorzystał nie tylko ICEfaces, ale również JBoss Seam, RichFaces, MyFaces i wiele innych bibliotek komponentów czy środowisk JSF). Koniecznie należy zarejestrować PersistentFacesServlet (wersja ICEfaces standardowego servletu FacesServlet) oraz BlockingServlet do obsługi asynchronicznych wywołań.

Kolejna strona - index.jspx - jest główną stroną aplikacji.

<?xml version="1.0" encoding="UTF-8"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ice="http://www.icesoft.com/icefaces/component" version="2.0">
<jsp:directive.page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" />
<f:view>
<html>
<head>
<title>Witaj ICEfaces</title>
</head>
<body>
<h3>Witaj ICEfaces</h3>
<p>Wciśnij przycisk poniżej i obserwuj ikonę stanu w przeglądarce oraz dziennik zdarzeń serwera aplikacyjnego.</p>
<ice:form partialSubmit="true">
<h:commandButton value="Wciśnij mnie" actionListener="#{ranking.zaglosuj}" />
</ice:form>
</body>
</html>
</f:view>
</jsp:root>
Baczne oko zauważy, że cały plik jest dobrze zbudowanym plikiem XHTML, stąd rozszerzenie jspx (domyślne dla dokumentów JSP, które są poprawnymi dokumentami XML). Jest to wymaganie ICEfaces, które nakłada na aplikację tworzenie stron JSP jako poprawnie zbudowanych dokumentów XML.

Strona index.jspx zawiera znaczniki ICEfaces rozpoczynające się nazwą ice.

Ciekawostką Eclipse IDE 3.3 z wtyczką Eclipse WTP 2.0.0 jest mechanizm podpowiedzi dla stron JSF.


Strona index.jspx wykorzystuje zarządzane ziarno JSF ranking. Definicja ziarna odbywa się w pliku faces-config.xml.

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<managed-bean>
<managed-bean-name>ranking</managed-bean-name>
<managed-bean-class>pl.jaceklaskowski.icefaces.ranking.beans.Ranking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>

Podczas edycji deskryptora aplikacji JSF - faces-config.xml - ujawniła się kolejna ciekawa funkcjonalność Eclipse IDE (a właściwie wtyczki Eclipse WTP 2.0.0) - graficzny edytor faces-config.xml.

Edytor posiada wiele widoków podłączonych do zakładek (u dołu zrzutu ekranu powyżej) i jest ciekawym i darmowym dodatkiem podczas tworzenia aplikacji JSF. Jak na kilka chwil z nim przyznaję, że zrobił na mnie pozytywne wrażenie.

Na koniec pozostaje przedstawić zarządzane ziarno JSF - ranking - reprezentowane przez klasę pl.jaceklaskowski.icefaces.ranking.beans.Ranking.

package pl.jaceklaskowski.icefaces.ranking.beans;

import javax.faces.event.ActionEvent;

public class Ranking {
public void zaglosuj(ActionEvent event){
System.out.println("oddano glos");
}
}
Mając wszystko zdefiniowane i gotowe do uruchomienia uruchamiamy aplikację wybierając menu Run As > Run on Server.

Poprawne uruchomienie Glassfisha i samej aplikacji wiąże się z wypisaniem wersji ICEfaces w dzienniku zdarzeń Glassfisha.

[#|2007-07-10T22:09:43.409+0200|INFO|sun-appserver9.1|com.icesoft.faces.application.D2DViewHandler|
_ThreadID=17;_ThreadName=httpWorkerThread-4848-1;|
ICEsoft Technologies, Inc.
ICEfaces 1.6.0
Build number: 15
Revision: 14409
|#]

A otworzenie strony pod adresem http://localhost:8080/icefaces-witajswiecie wita nas w następujący sposób.

Wciskając przycisk Wciśnij mnie można zauważyć, że ikona stanu przeglądarki niedrgnie, natomiast w dzienniku zdarzeń Glassfisha pojawi się następujący wpis:

[#|2007-07-10T22:11:05.049+0200|INFO|sun-appserver9.1|javax.enterprise.system.stream.out|
_ThreadID=24;_ThreadName=httpSSLWorkerThread-8080-1;|oddano glos|#]

Nie jest to wyrafinowana aplikacja JSF z użyciem ICEfaces, ale pozwala na dobry start przy tworzeniu kolejnych bardziej złożonych aplikacji w Eclipse IDE i Glassfish. Warto rozważyć wykorzystanie ICEfaces we własnych projektach korzystających z JSF, gdyż ICEfaces 1.6.0 jest zintegrowane z JBoss Seam 2.0.0.BETA (dostępny po zbudowaniu ze źródeł) oraz wspiera inne biblioteki jak chociażby facelets. Dodatkowo, podobnie jak JBoss Seam, ICEfaces wspiera koncepcję równoległego przetwarzania DOM, a to pozwala na uruchomienie wielu okien i zakładek przeglądarki do pracy z tą samą aplikacją.

Cały projekt dostępny jest jako icefaces-witajswiecie.zip. Wystarczy rozpakować w wybranym miejscu na dysku, zaimportować w Eclipse IDE i uruchomić. Uwag nie zgłaszać autorowi ;-)