Hier werden die Events des Produkts JSF Ext beschrieben.

Inhalt#

Übersicht#

Events sind eine Erweiterung des Action- und Update-Systems von JSF. Events können von der Java- und XHTML-Seite erzeugt und konsumiert werden.

NameJavaParameterBeschreibung
javax.faces.post_constructEvent.EVENT_POST_CONSTRUCTObject managedBeanDer Event wird nach dem Erzeugen einer managed Bean durch das JSF-System erzeugt.
javax.faces.pre_destroyEvent.EVENT_PRE_DESTROYDer Event wird vor dem Entfernen einer managed Bean erzeugt.
javax.faces.eventEvent.EVENT_EVENTString event, Object... argumentsDieser Meta-Event wird bei jedem Event erzeugt, sodass allgemeine Event-Handler geschrieben werden können. Dies ist mit Vorsicht zu verwenden.
javax.faces.messagesMessageHandler.EVENT-Der Event wird erzeugt, wenn Faces Messages vorliegen.
login.beforeLogin.EVENT_LOGIN_BEFORE-Bevor ein Benutzer eingeloggt wird.
login.successLogin.EVENT_LOGIN_SUCCESS-Nachdem ein Benutzer erfolgreich eingeloggt wurde. Der Benutzer ist über Login.instance().getUser() abrufbar.
login.failLogin.EVENT_LOGIN_FAIL-Nachdem ein Login fehlgeschlagen ist.
login.afterLogin.EVENT_LOGIN_AFTER-Nach dem Login-Prozess, unabhängig ob er erfolgreich oder fehlgeschlagen ist.
login.logoutLogin.EVENT_LOGOUT-Nach dem Logout.

Hintergrund#

In JSF werden oft Render-Attribute direkt in AJAX- und anderen Anweisungen angegeben. Da diese lose gekoppelt sind, wird im günstigen Fall eine Fehlermeldung entstehen, dass die entsprechende Id nicht mehr im Component Tree vorhanden ist. Der nachträgliche Einbau zusätzlich zu rendernder Components ist nicht vorgesehen, diese müssen explizit am Render-Attribut aller betreffenden Anweisungen hinzugefügt und gepflegt werden.

Aus diesem Grund führt JSF Ext die (Render-)Events ein. Events können zwar aus der View durch den Tag <e:raise> erzeugt werden, sinnvoll ist meist jedoch die Erzeugung durch die raise-Methode auf der Java-Seite. Dadurch bleibt die lose Kopplung von View und Controller erhalten. Die können Controller können Ereignisse auslösen, auf die sich Teile der View registrieren um neu gerendert zu werden.

Java#

Ein Event wird erzeugt, indem die Instanz von Event geholt wird. Dies kann durch @ManagedProperty("#{event}") geschehen oder durch die statische Methode Event.instance(). Dabei ist zu beachten, dass keine Session scoped Bean in einen Application Context injected wird.

Das Session basierte Event-Objekt enthält die Methode raise(String event, Object... arguments), also im einfachsten Fall:

	Event.instance().raise("com.intersult.some-event");

Die Events werden in der Regel durch eine Annotation konsumiert:

	@Listener("com.intersult.some-event")
	public void someEvent() {
	}

Es ist zu beachten, dass Events nur empfangen werden wenn eine Bean tatsächlich instantiiert ist.

FacesMessages#

Events können auch im XHTML verarbeitet werden, indem bestimmte Bereiche neu gerendert werden.

FacesMessages#

Zum Beispiel der vorgefertigte Event javax.faces.messages, der bei vorhandenen Faces-Messages ausgelöst wird:
<e:render event="javax.faces.messages" target="messages"/>
<h:messages id="messages" globalOnly="true"/>

Ergebnis: Die Faces-Messages werden gerendered, ohne dass bei jedem AJAX-Tag ein gesondertes Rendered-Attribut angegeben werden muss.

Hinweis: Hier wird der Render-Tag nicht im Messages-Tag verschachtelt, weil der Messages-Tag das Rendern von Child-Tags ausdrücklich verhindert.

Beispiel Input-Wrapper#

Situation: In einer Anwendung kommen zumeist verschiedene Eingabeelemente wie <h:inputText>, <h:selectOneMenu>, <h:inputSecret>, <h:selectBooleanCheckbox> sowie selbst gebaute Tags zur Verwendung. Für die Applikation besteht gewöhnlich ein einheitliches Layout mit AJAX- oder Client-Side Validierung, FacesMessages und weiteren Elementen.

Lösung bisher: In vielen Projekten wird für jedes Input-Element ein Composite-Tag gebaut, in dem der Code für AJAX, Validierung, Messages und so weiter wiederholt wird.

Mit JSF Ext kann ein generischer Wrapper für Input-Elements gebaut werden:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:c="http://java.sun.com/jsp/jstl/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:cc="http://java.sun.com/jsf/composite"
	xmlns:e="http://java.sun.com/jsf/ext"
	xmlns:ext="http://java.sun.com/jsf/composite/ext"
	xmlns:p="http://primefaces.org/ui"
>
	<cc:interface>
	</cc:interface>
	<cc:implementation>
		<e:insert component="#{cc.children[0]}">
			<f:ajax event="change"/>
		</e:insert>
		<h:message id="#{cc.children[0].id}-message" for=":#{cc.children[0].clientId}">
			<e:render for=":#{cc.children[0].clientId}"/>
		</h:message>
	</cc:implementation>
</html>

Die Anwendung dieses Composite-Tags ist dann wie folgt:

	<h:form id="form">
        <app:input id="text">
	    <h:inputText id="text" value="#{test.text}"/>
	</app:input>
        <h:commandButton value="Submit" action="#{bean.action}">
            <f:ajax/>
        </h:commandButton>

Erklärung: Die Composite-Component wrappt das Input-Element, welches innerhalb des Composite Tags durch <e:insert> eingefügt wird. Der Zugriff erfolgt dabei durch die EL-Expression cc.children[0].

Component FacesMessages#

JSF Ext generiert auch Events für Component FacesMessages, die entstehen beim Konvertieren, Validieren oder manuell in Java-Code. Oft wird unnötiger Weise das komplette Form neu gerendert, um die Component FacesMessages anzuzeigen. Mit JSF Ext können gezielt einzelne Messages gerendert werden, wenn diese auftreten. Um eine Komponenten durch eine Faces-Message rendern zu lassen, kann das for-Attribut verwendet werden:
<e:render for=":form:some-text"/>

Der Event tritt in folgenden Fällen auf:

  • Nur wenn die Component vom AJAX-Execute betroffen ist
  • Wenn eine FacesMessage für die Component zum ersten Mal vorhanden ist
  • Wenn eine FacesMessage für die Component zum zweiten oder öfteren Mal vorhanden ist
  • Wenn keine FacesMessage für die Component verschwunden ist

Hinweis: Das For-Attribut löst nur die Client-Id auf, das heißt es können relative Id's benutzt werden oder die @-Aliase. Letztlich entspricht es einem Event mit der vollen ClientId der Component, also <e:render for="text"/> hat denselben Effekt wie <e:render event=":form:panel:text"/>. Das Verwender des For-Attributs erleichtert allerdings den Bau der Komponenten und vermeidet Fehler, indem die Id validiert wird.

Raise Tag#

Events können hervorragend dazu benutzt werden, um AJAX-Submits und Rerendering voneinander zu trennen. Events werden dabei durch Components erzeugt und von anderen Components konsumiert. So braucht die erzeugende Component zur Erstellungszeit nicht wissen, welche Components rerendered werden:
<h:commandButton value="Submit">
	<f:ajax execute="@form"/>
	<e:raise name="com.intersult.test"/>
</h:commandButton>

Hinweis: Beim Raise-Tag handelt es sich um einen Action-Listener, der nur unterhalb einer Action-Source verwendet werden kann (Command-Button, -Link etc.) Bei vollen GET- oder POST-Requests macht Event gesteuertes Rendering keinen Sinn, da hier sowieso die komplette Seite gerendered werden würde. Was auch bei vollen Requests nützlist ist, sind @Listener-Methoden an Beans.

Der Raise-Tag unterstützt auch Parameter, die genauso wirken wie bei raise(event, param...):

    <e:raise name="com.intersult.test">
        <f:param value="#{cc.attrs.someParam}"/>
    </e:raise>

Das Konsumieren kann wieder auf ähnliche Weise erfolgen:

<h:outputText id="output" value="#{bean.text}">
	<e:render event="com.intersult.test"/>
</h:outputText>

Es ist zu beachten, dass bei der Update-Component (hier outputText) eine Id angegeben wird, damit der AJAX-Handler das Rerendering zuordnen kann. Dies tritt beim Verwenden des render-Attributs nicht auf, da durch die Angabe einer Id ja eine vergeben wurde.

Hinweise#

Events sind momentan Session-basiert, das heißt es existieren keine Application übergreifenden Events. Events sind eine Erweiterung des Action- und Update-Systems von JSF. Events können von der Java- und XHTML-Seite erzeugt und konsumiert werden.

NameJavaParameterBeschreibung
javax.faces.post_constructEvent.EVENT_POST_CONSTRUCTObject managedBeanDer Event wird nach dem Erzeugen einer managed Bean durch das JSF-System erzeugt.
javax.faces.pre_destroyEvent.EVENT_PRE_DESTROYDer Event wird vor dem Entfernen einer managed Bean erzeugt.
javax.faces.eventEvent.EVENT_EVENTString event, Object... argumentsDieser Meta-Event wird bei jedem Event erzeugt, sodass allgemeine Event-Handler geschrieben werden können. Dies ist mit Vorsicht zu verwenden.
javax.faces.messagesMessageHandler.EVENT-Der Event wird erzeugt, wenn Faces Messages vorliegen.
login.beforeLogin.EVENT_LOGIN_BEFORE-Bevor ein Benutzer eingeloggt wird.
login.successLogin.EVENT_LOGIN_SUCCESS-Nachdem ein Benutzer erfolgreich eingeloggt wurde. Der Benutzer ist über Login.instance().getUser() abrufbar.
login.failLogin.EVENT_LOGIN_FAIL-Nachdem ein Login fehlgeschlagen ist.
login.afterLogin.EVENT_LOGIN_AFTER-Nach dem Login-Prozess, unabhängig ob er erfolgreich oder fehlgeschlagen ist.
login.logoutLogin.EVENT_LOGOUT-Nach dem Logout.

Hintergrund#

In JSF werden oft Render-Attribute direkt in AJAX- und anderen Anweisungen angegeben. Da diese lose gekoppelt sind, wird im günstigen Fall eine Fehlermeldung entstehen, dass die entsprechende Id nicht mehr im Component Tree vorhanden ist. Der nachträgliche Einbau zusätzlich zu rendernder Components ist nicht vorgesehen, diese müssen explizit am Render-Attribut aller betreffenden Anweisungen hinzugefügt und gepflegt werden.

Aus diesem Grund führt JSF Ext die (Render-)Events ein. Events können zwar aus der View durch den Tag <e:raise> erzeugt werden, sinnvoll ist meist jedoch die Erzeugung durch die raise-Methode auf der Java-Seite. Dadurch bleibt die lose Kopplung von View und Controller erhalten. Die können Controller können Ereignisse auslösen, auf die sich Teile der View registrieren um neu gerendert zu werden.

Java#

Ein Event wird erzeugt, indem die Instanz von Event geholt wird. Dies kann durch @ManagedProperty("#{event}") geschehen oder durch die statische Methode Event.instance(). Dabei ist zu beachten, dass keine Session scoped Bean in einen Application Context injected wird.

Das Session basierte Event-Objekt enthält die Methode raise(String event, Object... arguments), also im einfachsten Fall:

	Event.instance().raise("com.intersult.some-event");

Die Events werden in der Regel durch eine Annotation konsumiert:

	@Listener("com.intersult.some-event")
	public void someEvent() {
	}

Es ist zu beachten, dass Events nur empfangen werden wenn eine Bean tatsächlich instantiiert ist.

FacesMessages#

Events können auch im XHTML verarbeitet werden, indem bestimmte Bereiche neu gerendert werden.

FacesMessages#

Zum Beispiel der vorgefertigte Event javax.faces.messages, der bei vorhandenen Faces-Messages ausgelöst wird:
<e:render event="javax.faces.messages" target="messages"/>
<h:messages id="messages" globalOnly="true"/>

Ergebnis: Die Faces-Messages werden gerendered, ohne dass bei jedem AJAX-Tag ein gesondertes Rendered-Attribut angegeben werden muss.

Hinweis: Hier wird der Render-Tag nicht im Messages-Tag verschachtelt, weil der Messages-Tag das Rendern von Child-Tags ausdrücklich verhindert.

Beispiel Input-Wrapper#

Situation: In einer Anwendung kommen zumeist verschiedene Eingabeelemente wie <h:inputText>, <h:selectOneMenu>, <h:inputSecret>, <h:selectBooleanCheckbox> sowie selbst gebaute Tags zur Verwendung. Für die Applikation besteht gewöhnlich ein einheitliches Layout mit AJAX- oder Client-Side Validierung, FacesMessages und weiteren Elementen.

Lösung bisher: In vielen Projekten wird für jedes Input-Element ein Composite-Tag gebaut, in dem der Code für AJAX, Validierung, Messages und so weiter wiederholt wird.

Mit JSF Ext kann ein generischer Wrapper für Input-Elements gebaut werden:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:c="http://java.sun.com/jsp/jstl/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:cc="http://java.sun.com/jsf/composite"
	xmlns:e="http://java.sun.com/jsf/ext"
	xmlns:ext="http://java.sun.com/jsf/composite/ext"
	xmlns:p="http://primefaces.org/ui"
>
	<cc:interface>
	</cc:interface>
	<cc:implementation>
		<e:insert component="#{cc.children[0]}">
			<f:ajax event="change"/>
		</e:insert>
		<h:message id="#{cc.children[0].id}-message" for=":#{cc.children[0].clientId}">
			<e:render for=":#{cc.children[0].clientId}"/>
		</h:message>
	</cc:implementation>
</html>

Die Anwendung dieses Composite-Tags ist dann wie folgt:

	<h:form id="form">
        <app:input id="text">
	    <h:inputText id="text" value="#{test.text}"/>
	</app:input>
        <h:commandButton value="Submit" action="#{bean.action}">
            <f:ajax/>
        </h:commandButton>

Erklärung: Die Composite-Component wrappt das Input-Element, welches innerhalb des Composite Tags durch <e:insert> eingefügt wird. Der Zugriff erfolgt dabei durch die EL-Expression cc.children[0].

Component FacesMessages#

JSF Ext generiert auch Events für Component FacesMessages, die entstehen beim Konvertieren, Validieren oder manuell in Java-Code. Oft wird unnötiger Weise das komplette Form neu gerendert, um die Component FacesMessages anzuzeigen. Mit JSF Ext können gezielt einzelne Messages gerendert werden, wenn diese auftreten. Um eine Komponenten durch eine Faces-Message rendern zu lassen, kann das for-Attribut verwendet werden:
<e:render for=":form:some-text"/>

Der Event tritt in folgenden Fällen auf:

  • Nur wenn die Component vom AJAX-Execute betroffen ist
  • Wenn eine FacesMessage für die Component zum ersten Mal vorhanden ist
  • Wenn eine FacesMessage für die Component zum zweiten oder öfteren Mal vorhanden ist
  • Wenn keine FacesMessage für die Component verschwunden ist

Hinweis: Das For-Attribut löst nur die Client-Id auf, das heißt es können relative Id's benutzt werden oder die @-Aliase. Letztlich entspricht es einem Event mit der vollen ClientId der Component, also <e:render for="text"/> hat denselben Effekt wie <e:render event=":form:panel:text"/>. Das Verwender des For-Attributs erleichtert allerdings den Bau der Komponenten und vermeidet Fehler, indem die Id validiert wird.

Raise-Component#

Events können hervorragend dazu benutzt werden, um AJAX-Submits und Rerendering voneinander zu trennen. Events werden dabei durch Components erzeugt und von anderen Components konsumiert. So braucht die erzeugende Component zur Erstellungszeit nicht wissen, welche Components rerendered werden:
<h:commandButton value="Submit">
	<f:ajax execute="@form"/>
	<e:raise name="com.intersult.test"/>
</h:commandButton>

Hier ist zu beachten, dass ein AJAX-Tag zusätzlich verwendet wird. Bei vollen GET- oder POST-Requests machen Events keinen Sinn, da hier sowieso die komplette Seite gerendered werden würde.

Das Konsumieren kann wieder auf ähnliche Weise erfolgen:

<h:outputText id="output" value="#{bean.text}">
	<e:render event="com.intersult.test"/>
</h:outputText>

Es ist zu beachten, dass bei der Update-Component (hier outputText) eine Id angegeben wird, damit der AJAX-Handler das Rerendering zuordnen kann. Dies tritt beim Verwenden des render-Attributs nicht auf, da durch die Angabe einer Id ja eine vergeben wurde.

Hinweise#

Events sind momentan Session-basiert, das heißt es existieren keine Application übergreifenden Events.