Mit sogenannten Push können Informationen aktiv an den Browser übertragen werden. Vor allem ist es dadurch möglich, eine Vielzahl von Benutzern gleichzeitig über ein Ereignis zu informieren.
Der Tag <e:socket> nutzt Web-Sockets um Browser-Push durchzuführen. Dies ist eine sehr effiziente Implementierung mit geringer Verzögerung zwischen dem Versenden der Nachricht und dem Eintreffen im Browser, sowie Netzwerk und Ressourcen schonend. Dies ist möglich, wenn der Web-Server den Web-Standard 3.0 beherrscht (z.B. ab Tomcat 7). Sind Web-Sockets nicht verfügbar aufgrund eines Web-Servers kleiner als 3.0, weil der Browser dies nicht beherrscht oder ein dazwischen liegender Proxy es nicht unterstützt, wird die Comet-Engine verwendet, die Long-Polling durchführt.
Dazu ist folgende Dependency zum Projekt hinzuzufügen:
<dependency> <groupId>org.atmosphere</groupId> <artifactId>atmosphere-runtime</artifactId> <version>2.1.0-beta1</version> </dependency>
<h:form id="form"> <h:commandButton value="Senden" action="#{pushTest.action}"> <f:ajax render=":test:value"/> </h:commandButton> </h:form> <e:push id="test" direct="true"> <h:panelGrid id="panel" columns="2"> <h:outputText id="text" value="Test"/> <h:outputText id="value" value="#{pushTest.count}"/> </h:panelGrid> </e:push>
Erklärung: Der Tag ":test:value" wird durch eine einfache AJAX-Render-Anweisung auf allen verbundenen Clients neu gerendert.
Eigenschaft | Direct Mode | AJAX Mode |
---|---|---|
Rendering | Inhalt wird nur bei dem Client gerendert, der den Event ausgelöst hat | Inhalt wird für jeden Client gerendert |
Effizienz | Effizienter Modus, da das HTML-Update direkt an alle Clients geschickt werden kann | Rendering wird für jeden Client getrennt gerendert |
Inhalt | Inhalt ist für jeden Client identisch | Inhalt kann für jeden Client individualisiert werden |
Daten | Anzeige von Daten die für mindestens eine Gruppe bestimmt oder öffentlich ist | Anzeige privater Daten möglich |
Auslöser | Auslöser ist ein Faces-Event | Auslöser kann ein Faces-Event, Timer oder beliebiger anderer Event sein |
Damit ist es beispielsweise möglich, eine Tabelle zu erzeugen und einzelne Zellen per Push upzudaten.
Warnung: Channel-Name und Push-Tag sollte für alle Clients übereinstimmen, damit die Inhalte übereinstimmen. Andernfalls kommt es zu sogenannten Cross-Talking - der Inhalt des Push-Tags ändert sich.
<e:socket channel="/test"> <f:ajax render=":push-form:chat"/> </e:socket>
Auf der Java-Seite wird der Socket dann so angesprochen:
PushContext.instance().push("/test");
Hinweis: In vielen Fällen reicht die reine Benachrichtigung des Client aus, weil dieser dann per AJAX-Call eine Server-Anfrage startet. Dies bietet den Vorteil, dass die Session und der FacesContext des entsprechenden Benutzers verfügbar ist.
Die Socket-Component unterstützt folgende Attribute und Behaviors:
Attribut | Beschreibung |
---|---|
channel | Das Attribut wird benötigt und beschreibt den Kommunikationskanal zum Server. Indem der Server diesen Channel informiert, wird im Browser eine Nachricht ausgeliefert. Die Besonderheit am Channel ist, dass dieser von beliebig vielen Browsern d.h. eingeloggten Benutzern abonniert werden kann. Der Server braucht daher nicht zu wissen, wieviele Clients überhaupt die Nachricht empfangen werden. |
onopen | Der Event wird beim Öffnen des Channels ausgelöst. Der Client weiß so immer, ob er verbunden ist oder nicht. Dadurch kann dem Nutzer auch ein Verbindungsstatus angezeigt werden. |
onclose | Das Gegenstück zu onopen, wird aufgerufen, wenn die Verbindung abbricht. Im normalen Produktivbetrieb wird diese Methode nur in Ausnahmefällen aufgerufen. |
onmessage | Dies ist der eigentliche Push-Aufruf. Wenn am Server PushContext.push() aufgerufen wird, wird am Client dieses JavaScript-Behavior ausgelöst. |
onerror | Hier kann eine Fehlerbehandlung hinzugefügt werden, zum Beispiel dem Benutzer angezeigt werden, wenn ein Problem mit der Verbindung auftaucht. |
PushContext.instance().push("/test");
PushContext.instance().push("/test", parameter);
Auf der Client-Seite kann der Parameter dann wie folgt entgegen genommen werden:
<e:socket channel="/test" onmessage="alert(response.responseBody);">
ProxyPass /<context-path>/faces/javax.faces.resource/<channel> ws://<ziel>/<context-path>/faces/javax.faces.resource/<channel> ProxyPassReverse /<context-path>/faces/javax.faces.resource/<channel> ws://<ziel>/<context-path>/faces/javax.faces.resource/<channel>
Erklärung: Die Web-Socket-Protokolle WS werden vor den eigentlichen Proxy-Einträgen für die Application abgefangen und mit dem WS-Protokoll umgeleitet. In Apache 2.4 steht dafür das Modul mod_proxy_wstunnel.so zur Verfügung.
#{resource['<library>:<name>']}
zu erzeugen oder ganz zu Fuß mit
#{request.contextPath}/faces/javax.faces.resource/<name>?ln=<library>
Möchte man einen Link erzeugen vom Schema <a href="...">, bietet JSF Ext eine schönere Lösung:
<e:resourceLink name="<name>" library="<library"> <h:outputText value="Some link"/> </e:resourceLink>
Hinweis: Wie der normale <h:outputLink> unterstützt <h:resourceLink> ebenfalls Parameter vom Typ <f:param> (und abgeleitete Parameter wie <f:method-param> und <f:new>).