Problem
Websphere 7 als Java-EE5-Applikationsserver bietet keine JSF-2.0-Implementierung an – zu Zeiten von Java-EE5 war noch JSF 1.2 aktuell. Wie es denoch geht, will ich hier zeigen.
Websphere 7 als Java-EE5-Applikationsserver bringt zwei JSF-1.2-Implementierungen mit – eine (leicht modifizierte) Sun-Referenz-Implementierung und MyFaces. Wer bereits mit JSF 2.0 gearbeitet hat, wird den Weg zurück nach JSF 1.2 sicher nicht gehen wollen, deshalb habe ich hier die Schritte aufgeschrieben, die notwendig sind, um Websphere 7 (und auch WS8!) JSF 2.0 mit Richfaces schmackhaft zu machen.
Lösung
1. Die zu deployende WAR/EAR-Datei muss Mojarra 2.0.4 oder 2.0.8 (nicht 2.1.x, nicht 2.0.2) enthalten.
In der Regel ist das eine jsf-api.jar und eine jsf-impl.jar (manchmal auch eine einzelne Datei namens javax.faces-2.x.x.jar).
Diese JSF-Implementierung (Mojarra 2.0.4) kommt in das Verzeichnis WEB-INF/lib.
Wer Maven nutzt, kann folgende Dependency hinzufügen:
<dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.0.4</version> </dependency>
Neuere Versionen von JSF (2.1.+) benötigen die Servlet-API 3.0, die
normaler Weise nur bei JavaEE6-Servern zu finden ist.
Versucht man, andere Versionen als die JSF 2.0.4/2.0.8 zu nutzen, dann steigt
die Web-Anwendung mglw. mit folgender Fehlermeldung im Log aus:
javax.servlet.ServletException: SRVE0207E: Es wurde eine nicht abgefangene Initialisierungsausnahme vom Servlet erstellt. at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:434) at com.ibm._jsp._index._jspService(_index.java:85) Caused by: java.lang.IllegalStateException: Die Anwendung wurde bei Systemstart nicht einwandfrei initialisiert, Factory konnte nicht gefunden werden: javax.faces.context.FacesContextFactory. Rügriff versucht. at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:270)
2. Die web.xml muss folgenden Eintrag enthalten, um JSF zu initialisieren:
<listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener>
Im Websphere-Log (%websphere%/profiles/AppSrv01/logs/server1/SystemOut.log) wird der Start
von JSF 2.0.4 mitgeloggt:
[29.01.12 01:36:08:000 CET] 0000001b config I Mojarra 2.0.4 (FCS b09) für Kontext '/CompositeComp' wird initialisiert.
3. Der Websphere-Log beklagt sich über eine fehlende Zuweisung des Mime-Typs für xhtml, für den Fall, dass Dateien mit der Endung .xhtml als JSF-Datei erkannt werden.
Dazu muss in der (applikationsbezogenen oder der allgemeinen) web.xml folgender Eintrag hinzugefügt werden:
<mime-mapping> <extension>xhtml</extension> <mime-type>application/xhtml+xml</mime-type> </mime-mapping>
4. Wir fügen unserem Projekt Richfaces hinzu.
Getting Started
Der Websphere-Log gibt jetzt u.a. folgende Warnung aus:
[29.01.12 01:36:10:015 CET] 0000001b Config W org.richfaces.javascript.ClientServiceConfigParser parse Found JavaScript function definition for class javax.validation.constraints.NotNull, but that class is not presented
Möchte man javascriptseitige Bean-Validierung (JSR330) nutzen, dann sind diese JAR-Dateien noch nach WEB-INF/lib zu kopieren:
* validation-api.jar (version 1.0.0.GA)
* hibernate-validator.jar (version 4.2 or higher)
Siehe http://docs.jboss.org/richfaces/latest_4_1_X/
Developer_Guide/en-US/html/chap-Developer_Guide-Getting_started_with_RichFaces.html
Natürlich kann man sich diesen Schritt sparen, wenn nur serverseitig (und nicht per JS) validiert wird.
Validation-API:
<groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version>
Hibernate-Validator:
<artifactId>hibernate-validator-parent</artifactId> <groupId>org.hibernate</groupId> <version>4.2.0.Final</version>
5. Es wird allgemein empfohlen, eine “Gemeinsam genutzte isolierte Bibliothek” anzulegen, falls nicht die mit dem Websphere mitgelieferten JSF-Implementierungen (JSF1.2 und MyFaces) genutzt werden, sondern externe.
In meinem Fall hat das nicht geklappt. Es ging nur dann, wenn ich meiner WAR-Datei die JSF-Dateien hinzugefügt und den Listener in der web.xml eingestellt hatte.
So geht’s laut IBM:
JavaServer-Faces-Implementierung konfigurieren
6. Es wird immer noch der EL-Parser von IBM genommen, so dass die Auswertung von Methoden-Parametern nicht möglich ist. Ein #{myBean.write(‘Hallo’)} führt folglich zu einem Fehler.
org.apache.el.parser.ParseException: Encountered "(" at line 1, column 22. Was expecting one of: "}" ... "." ... "[" ... ">" at org.apache.el.parser.ELParser.generateParseException(ELParser.java:2142)
Wir müssen jetzt also auch den EL-Parser aktualisieren. Wie das geht, wird dort beschrieben:
http://rueprich.de/bloggt/2010/06/expression-language-2-2-mit-maven-und-tomcat
<dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>el-impl</artifactId> <version>2.2</version> </dependency>
web.xml:
<context-param> <param-name>com.sun.faces.expressionFactory</param-name> <param-value>com.sun.el.ExpressionFactoryImpl</param-value> </context-param>
Im Websphere-Log erscheint folgende Warnung:
I JSF1027: [null Die ELResolvers für JSF wurden nicht im JSP-Container registriert.
Diese Meldung werde ich ignorieren, da ich jetzt dank JSF 2.0 kein JSP mehr verwenden muss.
7. Sich freuen über eine aktuelle JSF-2.0-Implementierung mit ebenso aktueller Expression
Language.
Was bringt die Akutalisierung auf JSF 2.0 für den Entwickler?
Ich will die aus meiner Sicht wichtigen Veränderungen an Minibeispielen kurz aufzeigen:
* ManagedBean und ManagedProperty via Annotation statt über XML-Dateien.
In JSF 1.2 sind ManagedBeans aufwändig zu konfigurieren. Neben der Java-Klasse
selbst hat man noch eine Menge XML-Konfiguration vor sich:
faces-config.xml:
<managed-bean> <managed-bean-name>carBean</managed-bean-name> <managed-bean-class>de.triona.view.CarBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>bikeBean</property-name> </managed-property> </managedBean> <managed-bean> <managed-bean-name>bikeBean</managed-bean-name> <managed-bean-class>de.triona.view.BikeBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managedBean>
In JSF 2.0 reduziert sich das auf eine Java-Klasse mit Annotationen:
@ManagedBean @SessionScoped public class CarBean { @ManagedProperty(value="bikeBean") BikeBean bikeBean; }
* Direkte Navigation an Stelle der indirekten Navigation in faces-config.xml
* Die AJAX-Komponente f:ajax
Bsp.:
<h:inputText value="#{bean.text}"> <f:ajax event="keyup" execute="@this" render="out"/> </h:inputText> <!-- Dieses Textfeld wird jetzt bei jedem KeyUp-Event neu gerendert--> <h:outputText id="out" value="#{bean.text}"/>
Fazit
JSF 2.0 auf dem Websphere 7 ist mit einiger Mühe machbar.
Aber:Bei meinen Tests auf verschiedenen Rechnern gab es manchmal
Probleme und das Ende der Fahnenstange war doch das mitgelieferte JSF 1.2 –
je nach Patchversion des WS und der mitgelieferten Libraries der Anwendung.
Daher ist die Devise: ausprobieren!