Quantcast
Channel: OmniFaces & JSF Fans
Viewing all articles
Browse latest Browse all 74

JSF 2.3 - The WebSocket Quickstart under Payara

$
0
0
Read also:

JSF 2.3 - Explicitly open/close a websocket channel
JSF 2.3 - Conditionally open/close a websocket channel
JSF 2.3 - Firing one-time push when the web socket channel has been opened
JSF 2.3 - Multiple File Upload with HTML 5, AJAX and upload progress bar via web sockets

Starting with JSF 2.3-m05 we can take advantage of a brand new feature - register a web socket push connection in client side. Thanks to the JSF team (especially to Bauke Scholtz (aka BalusC)) this feature is available in today milestone via <f:websocket/>tag.

In this post, let's see a minimal usage of <f:websocket/> tag.

In JSF page, we need to add the <f:websocket/> tag with its two required attributes:

·         channel- This is javax.el.ValueExpressionthat must be evaluated to Stringand it represents the name of the web socket channel. A channel name is restricted to alphanumeric characters, hyphens, underscores and periods. A channel can have multiple open web sockets, and each of these sockets will receive the same push notification from the server.
·         onmessage- This is javax.el.ValueExpressionthat must be evaluated to Stringand it represents the a JavaScript listener function that is automatically invoked when a push notification is received from the server.

The signature of the listener function for onmessage is of type:

function fooListener(message, channel, event) {                      
 // message - the message pushed by the server
 // channel - the channel name
 // event - the raw MessageEvent instance
}

So, a simple <f:websocket/>tag usage will look like this:

<f:websocket channel="clock" onmessage="socketListener" />

<div id="clockId"></div>

<script type="text/javascript">
 function socketListener(message, channel, event) {                      
  document.getElementById("clockId").innerHTML += message + "<br/>";
 }
</script>

By default, when we start the application, the web socket is automatically connected and open. As long as the document is open the web socket is open. When the document is unloaded the web socket is automatically closed. In the web socket is initially successfully connected but the connection is closed as a result of e.g. a network error or server restart, JSF will try to auto-reconnect it at increasing intervals.

Now, let's focus on the server side. Here we have to take into account the push messages mechanism. This mechanism is based on javax.faces.push.PushContext interface and javax.faces.push.PushAPI.

First, you need to know that by default the web socket is application scoped. This means that the managed bean that can push messages to this web socket must be in application scope (annotated with @ApplicationScope). In this case, the push message can be sent by all users and the application itself.

Furthermore, you have to inject PushContext via @Push annotation on the given channel name in any CDI/container managed artifact. For example:

@Inject
@Push(channel = "clock")
private PushContext push;

Finally, we need to write an action method capable to push messages to web socket via PushContext. For example:

public void clockAction(){
 Calendar now = Calendar.getInstance();
       
 String time = now.get(Calendar.HOUR_OF_DAY) + ":" +
               now.get(Calendar.MINUTE) + ":" +
               now.get(Calendar.SECOND);
 LOG.log(Level.INFO, "Time: {0}", time);
    
 push.send(time);
}

Let's glue everything together. First, the JSF page:

<h:body>        
 <h:form>           
  <h:commandButton value="Clock" action="#{pushBean.clockAction()}">
   <f:ajax />
  </h:commandButton>
 </h:form>

 <f:websocket channel="clock" onmessage="socketListener" />       

 <hr/>
 <div id="clockId"></div>

 <script type="text/javascript">
  function socketListener(message, channel, event) {                      
   document.getElementById("clockId").innerHTML += message + "<br/>";
  }
 </script>   
</h:body>

Next, our simple CDI bean:

@Named
@ApplicationScoped
public class PushBean implements Serializable {
   
 private static final Logger LOG = Logger.getLogger(PushBean.class.getName());
       
 @Inject
 @Push(channel = "clock")
 private PushContext push;
   
 public void clockAction(){
  Calendar now = Calendar.getInstance();
       
  String time = now.get(Calendar.HOUR_OF_DAY) + ":" +
                now.get(Calendar.MINUTE) + ":" + now.get(Calendar.SECOND);
  LOG.log(Level.INFO, "Time: {0}", time);
       
  push.send(time);
 }
}

Finally, the m05 requires the following settings in web.xml:

<context-param>
 <param-name>javax.faces.ENABLE_CDI_RESOLVER_CHAIN</param-name>
 <param-value>true</param-value>
</context-param>   
<context-param>
 <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name>
 <param-value>true</param-value>
</context-param>

Done! The complete application was tested under Payara server and it is available here.

Viewing all articles
Browse latest Browse all 74

Trending Articles