Tworzenie aplikacji z JavaServer Faces, Apache Maven i Apache Geronimo
Z Jacek Laskowski - Wiki Projektanta Java EE
Nadanie certyfikacji zgodności ze specyfikacją Java Enterprise Edition 5 (Java EE 5) serwerowi Apache Geronimo 2.0 nie może pozostać bez echa i tym artykułem chciałbym rozpocząć serię artykułów przedstawiających jego możliwości. Rozpoczniemy delikatnie - od stworzenia aplikacji korzystającej z JavaServer Faces 1.2 oraz wtyczki Apache Maven do Apache Geronimo 2.0. Będzie to aplikacja typu Witaj Świecie, która pozwoli na zestawienie środowiska do budowania bardziej zaawansowanych aplikacji z pomocą Java EE 5. Wiele pisze się o uproszczeniach przy budowaniu aplikacji korporacyjnych wykorzystujących możliwości specyfikacji Java EE 5, więc przekonajmy się jak owe obietnice realizowane są przez Apache Geronimo 2.0. Przekonajmy się, czy obietnice prostszego budowania aplikacji korporacyjnych są jedynie obietnicami, czy faktem.
Wersje oprogramowania w środowisku uruchomieniowym:
- Apache Geronimo 2.0M6
- Apache Maven 2.0.6
- (opcjonalnie) Eclipse IDE 3.3RC4
Zakłada się, że powyższe oprogramowanie jest zainstalowane i działa poprawnie. Instalacja oprogramowania sprowadza się do pobrania i rozpakowania paczek w wybranym katalogu.
Kompletny projekt jest dostępny jako jsf-witajgeronimo.zip.
Spis treści |
Utworzenie projektu aplikacji internetowej - jsf-witajgeronimo
Apache Maven 2 (m2) udostępnia szeregu uproszczeń przy zarządzaniu projektem aplikacji dowolnego typu, w tym i aplikacji internetowych. Działanie m2 oparte jest o mechanizm wtyczek, które pozwalają na realizowanie powtarzających się zadań administracyjnych. Jednym z nich jest utworzenie przestrzeni projektowej. Wykonujemy polecenie mvn archetype:create w wybranym przez siebie katalogu, np. C:\.
$ mvn archetype:create -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=pl.jaceklaskowski.jsf.witajgeronimo -DartifactId=jsf-witajgeronimo [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] ---------------------------------------------------------------------------- [INFO] Building Maven Default Project [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] ---------------------------------------------------------------------------- ... [INFO] Archetype created in dir: c:\jsf-witajgeronimo [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Sun Jun 17 00:35:02 CEST 2007 [INFO] Final Memory: 5M/254M [INFO] ------------------------------------------------------------------------
Przechodzimy do katalogu jsf-witajgeronimo.
$ cd jsf-witajgeronimo
Kolejne polecenia wydawane będą właśnie z tego katalogu, który reprezentuje nasz projekt aplikacji internetowej.
Wykonujemy polecenie mvn eclipse:eclipse, aby utworzyć pliku projektu do importu projektu do Eclipse. W zależności od wybranego graficznego środowiska programistycznego (IDE) polecenie może nieznacznie się różnić. W przypadku NetBeans IDE 6.0M9 nie jest w ogóle konieczne, gdyż NetBeans IDE wspiera projekty zarządzane przez m2.
$ mvn eclipse:eclipse [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'eclipse'. [INFO] ---------------------------------------------------------------------------- [INFO] Building jsf-witajgeronimo Maven Webapp [INFO] task-segment: [eclipse:eclipse] [INFO] ---------------------------------------------------------------------------- ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1 second [INFO] Finished at: Sun Jun 17 00:39:00 CEST 2007 [INFO] Final Memory: 3M/254M [INFO] ------------------------------------------------------------------------
Komunikat BUILD SUCCESSFUL wskazuje na poprawnie wykonane polecenie. Uruchamiamy Eclipse IDE i importujemy projekt (File > Import > Existing Projects into Workspace).
UWAGA: Może się zdarzyć, że po imporcie pojawi się komunikat ostrzegawczy - Unbound classpath variable: 'M2_REPO/junit/junit/3.8.1/junit-3.8.1.jar' in project jsf-witajgeronimo - co oznacza brak definicji zmiennej M2_REPO w wybranej przestrzeni roboczej. Mimo, że Eclipse zgłasza to jako komunikat ostrzegawczy, po dodaniu kolejnych zależności w projekcie nie będzie możliwe tworzenie klas korzystających z nich z poziomu Eclipse. Naprawiamy błąd poprzez Window > Preferences... > Java > Build Path > Classpath Variables > New.... Dodajemy M2_REPO ze wskazaniem na lokalne repozytorium M2, potwierdzamy ponowne przebudowanie projektu i voila - projekt jest czysty, bez jakichkolwiek komunikatów ostrzegawczych, gotowy do dalszego rozwoju.
Dodanie zależności projektowych w pliku pom.xml
Głównym elementem projektu zarządzanego przez m2 jest deskryptor projektu - pom.xml - znajdujący się w katalogu głównym projektu. W nim definiujemy zależnosci projektowe. Jedną z zależności są biblioteki, z których będzie korzystał projekt. W naszym przypadku będą to zależności związane z Apache Geronimo oraz JSF.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.jaceklaskowski.jsf.witajgeronimo</groupId>
<artifactId>jsf-witajgeronimo</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>Witaj Geronimo z JavaServer Faces 1.2 i Apache Maven 2</name>
<url>http://www.JacekLaskowski.pl</url>
<properties>
<geronimoHome>c:/apps/geronimo-tomcat6-jee5-2.0-M6</geronimoHome>
<options>verbose</options>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.geronimo.plugins</groupId>
<artifactId>geronimo-maven-plugin</artifactId>
<executions>
<execution>
<id>undeploy-module-pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>undeploy-module</goal>
</goals>
<configuration>
<modules>
<module>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
<type>war</type>
</module>
</modules>
</configuration>
</execution>
<execution>
<id>deploy-module</id>
<phase>pre-integration-test</phase>
<goals>
<goal>deploy-module</goal>
</goals>
<configuration>
<moduleArchive>${project.build.directory}/${artifactId}-${version}.war</moduleArchive>
</configuration>
</execution>
<execution>
<id>list</id>
<phase>pre-integration-test</phase>
<goals>
<goal>list-modules</goal>
</goals>
</execution>
<execution>
<id>undeploy-module-post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>undeploy-module</goal>
</goals>
<configuration>
<modules>
<module>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
<type>war</type>
</module>
</modules>
</configuration>
</execution>
</executions>
<configuration>
<reporters>
<reporter implementation="org.apache.geronimo.mavenplugins.geronimo.reporting.SurefireReporter">
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
</reporter>
</reporters>
<optionSets>
<optionSet>
<id>verbose</id>
<properties>
<property>
<name>verbose</name>
<value>true</value>
</property>
</properties>
</optionSet>
</optionSets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>java.net repository</id>
<name>java.net Maven 1.x Repository</name>
<url>https://maven-repository.dev.java.net/nonav/repository/</url>
<layout>legacy</layout>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>1.2_04-p02</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Ważnym elementem integracji projektu z Apache Geronimo jest definicja katalogu domowego serwera w zmiennej geronimoHome. Upewnij się, że wartość zmiennej wskazuje na właściwy katalog, w którym zainstalowano Apache Geronimo 2.0.
Zależność od biblioteki JSF - jsf-impl-1.2_04-p02.jar - jest w zasięgu provided, gdyż biblioteka jest częścią środowiska serwera aplikacyjnego Java EE 5 i zgodnie ze specyfikacją nie powinna znajdować się w aplikacji internetowej.
Większa część pliku pom.xml zawiera konfigurację wtyczki org.apache.geronimo.plugins.geronimo-maven-plugin, która opisana jest w dokumencie About Geronimo Maven2 Plugins :: Geronimo. Dzięki niej wykonamy krok instalacyjny oraz podczas jego wykonania m2 wypisze wszystkie zainstalowane moduły (aplikacje) w celach diagnostycznych.
Rozbudowanie aplikacji internetowej o funkcjonalność JSF
Deskryptor aplikacji internetowej - web.xml
Sercem aplikacji internetowej jest deskryptor web.xml. Do poprawnego działania JSF wymagane jest zarejestrowanie servletu javax.faces.webapp.FacesServlet oraz związanie go z częścią adresów w aplikacji. Istotne jest również podniesienie wersji aplikacji do 2.5 za pomocą atrybutu version, co instruuje serwer aplikacyjny o wykorzystywanej wersji specyfikacji Java EE 5, a w zasadzie Java Servlet 2.5.
<web-app 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-app_2_5.xsd"
metadata-complete="false" version="2.5">
<display-name>Witaj Geronimo z JavaServer Faces 1.2 i Apache Maven 2</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Plik web.xml w projekcie znajduje się w katalogu src/main/webapp/WEB-INF.
Plik konfiguracyjny aplikacji - geronimo-web.xml
Elementem opcjonalnym, jednakże znacząco upraszczającym zarządzanie aplikacją, jest plik geronimo-web.xml, który tworzymy w katalogu src/main/webapp/WEB-INF, obok web.xml. Wskazuje on nazwę dla aplikacji w ramach serwera i służy wyłącznie celom administracyjnym.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.1"
xmlns:naming="http://geronimo.apache.org/xml/ns/naming-1.1">
<dep:environment>
<dep:moduleId>
<dep:groupId>${groupId}</dep:groupId>
<dep:artifactId>${artifactId}</dep:artifactId>
<dep:version>${version}</dep:version>
<dep:type>war</dep:type>
</dep:moduleId>
</dep:environment>
</web-app>
Strona główna aplikacji - index.jsp
Plikiem związanym bezpośrednio z samą funkcjonalnością aplikacji jest plik index.jsp, który znajduje się w katalogu src/main/webapp. Reprezentuje on stronę główną aplikacji internetowej.
<%@ page contentType="text/html; charset=ISO-8859-2"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view locale="pl">
<f:loadBundle var="komunikat" basename="pl.jaceklaskowski.jsf.witajswiecie.Komunikaty" />
<head>
<title><h:outputText value="#{komunikat['powitanie']}" /></title>
</head>
<body>
<center>
<a href="http://geronimo.apache.org"><img src="http://geronimo.apache.org/index.data/glogo-med_2.gif" border="0" /></a>
<br>
<h1><h:outputText value="#{komunikat['powitanie']}" /></h1>
</center>
</body>
</f:view>
Plik komunikatów - Komunikaty_pl.properties
Na stronie głównej aplikacji - index.jsp - skorzystaliśmy z mechanizmu dostosowania treści do ustawnień językowych klienta za pomocą elementu f:loadBundle. Uzupełnieniem mechanizmu jest plik komunikatów - Komunikaty_pl.properties, który umieszczamy w katalogu src/main/resources/pl/jaceklaskowski/jsf/witajswiecie.
Zawartość pliku Komunikaty_pl.properties przedstawia się następująco.
powitanie=Witaj Geronimo z JavaServer Faces 1.2 i Apache Maven 2.0
Uruchomienie Apache Geronimo
Istnieje możliwość uruchomienia Apache Geronimo z poziomu Apache Maven w ramach wykonywania testów integracyjnych, jednakże dla naszych celów chcielibyśmy, aby serwer działał dłużej niż na czas testów, które wykonywane byłyby automatycznie przez m2 i skorzystamy ze skryptów dostarczanych przez Geronimo.
Uruchom polecenie ./bin/geronimo.sh run -vv w katalogu domowym Geronimo. W zasadzie parametr -vv nie jest potrzebny i służy wyłącznie zwiększeniu ilości komunikatów wypisywanych na konsolę, co może znacząco uprościć rozwiązywanie problemów, kiedy się pojawią. Po kilku sekundach serwer powinien wypisać komunikat Geronimo startup complete.
$ ./bin/geronimo.sh run -vv Using GERONIMO_BASE: c:\apps\geronimo-tomcat6-jee5-2.0-M6 Using GERONIMO_HOME: c:\apps\geronimo-tomcat6-jee5-2.0-M6 Using GERONIMO_TMPDIR: c:\apps\geronimo-tomcat6-jee5-2.0-M6\var\temp Using JRE_HOME: c:\apps\java5\jre 01:27:43,046 DEBUG [BasicKernel] Starting boot 01:27:43,328 DEBUG [GBeanInstanceState] GBeanInstanceState for: geronimo/boot/none/car?role=kernel State changed from stopped to starting 01:27:43,328 DEBUG [GBeanInstanceState] GBeanInstanceState for: geronimo/boot/none/car?role=kernel State changed from starting to running 01:27:43,328 DEBUG [BasicKernel] Bootedmvn install geronimo:deploy-module ... Geronimo startup complete
Zatrzymanie serwera to wydanie polecenia ./bin/geronimo.sh stop, bądź po prostu wciśnięcie kombinacji klawiszy Ctrl-C w konsoli, z której wystartowano serwer.
Uruchomienie aplikacji internetowej - jsf-witajgeronimo
W naszym przypadku wykonanie kroku instalacji aplikacji zlecimy m2 poprzez wtyczkę org.apache.geronimo.plugins.geronimo-maven-plugin. Konfigurację działania wtyczki opisano w pliku pom.xml. Z tak przygotowanym pom.xml wystarczy wydać polecenie mvn clean integration-test, aby aplikacja została zainstalowana i uruchomiona na serwerze Geronimo (zanim nastąpi faktyczna instalacja aplikacji m2 będzie próbował ją najpierw odinstalować z serwera).
$ mvn clean integration-test
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Witaj Geronimo z JavaServer Faces 1.2 i Apache Maven 2
[INFO] task-segment: [clean, integration-test]
[INFO] ----------------------------------------------------------------------------
...
[INFO] [war:war]
[INFO] Exploding webapp...
[INFO] Assembling webapp jsf-witajgeronimo in c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0
[INFO] Copy webapp webResources to c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0
[INFO] Copy webapp webResources to c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0
[INFO] Generating war c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0.war
[INFO] Building war: c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0.war
...
[INFO] [geronimo:undeploy-module {execution: undeploy-module-pre-integration-test}]
log4j:WARN No appenders could be found for logger (org.apache.geronimo.kernel.config.ConfigurationUtil).
log4j:WARN Please initialize the log4j system properly.
[INFO] Module is already stopped: pl.jaceklaskowski.jsf.witajgeronimo/jsf-witajgeronimo/1.0/war
[INFO] Module is not deployed: pl.jaceklaskowski.jsf.witajgeronimo/jsf-witajgeronimo/1.0/war
[INFO] [geronimo:deploy-module {execution: deploy-module}]
[INFO] Using non-artifact based module archive: c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0.war
[INFO] Using non-artifact based plan: null
[INFO] Distributing module artifact: c:\jsf-witajgeronimo\target\jsf-witajgeronimo-1.0.war with plan null
[INFO] Starting modules...
[INFO] Starting module: pl.jaceklaskowski.jsf.witajgeronimo/jsf-witajgeronimo/1.0/war
[INFO] Started module(s):
[INFO] [0] pl.jaceklaskowski.jsf.witajgeronimo/jsf-witajgeronimo/1.0/war
[INFO] [geronimo:list-modules {execution: list}]
[INFO]
[INFO] Running Modules
[INFO] ===============
...
[INFO] [42] pl.jaceklaskowski.jsf.witajgeronimo/jsf-witajgeronimo/1.0/war; URL: http://localhost:8080/jsf-witajgeronimo-1.0
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 55 seconds
[INFO] Finished at: Sun Jun 17 01:36:54 CEST 2007
[INFO] Final Memory: 13M/254M
[INFO] ------------------------------------------------------------------------
W ramach instalacji prezentowany jest adres zainstalowanej aplikacji - http://localhost:8080/jsf-witajgeronimo-1.0.
Otwierając przeglądarkę wskazujemy podany adres http://localhost:8080/jsf-witajgeronimo-1.0/faces/index.jsp i (zakładając, że nie pojawiły się problemy) naszym oczom ukaże się pierwsza strona aplikacji internetowej.
