luni, 28 martie 2016

JSF 2.3 - Firing one-time push when the web socket channel has been opened

Read also:

WebSocket integration by Arjan Tijms


In this post, we want to write an application that uses a web socket to "say" Hello world! - pushes the Hello World! message to a channel named hello. This should take place automatically (when the channel has been opened) and one-time only.

Since a web socket channel is automatically opened, we don't need to put any effort in this step. We just define in page a simple web socket like below:

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

Note: In such cases, we should use this together with the optional user attribute of  <f:websocket/> to push the message to a specific user that it is login. Moreover, we can use the optional scope attribute set to session (push messages to all views in the current user session only) or view (push messages to  to the current view only). In such cases, the CDI managed bean should be annotated with the CDI @SessionScoped respectively @ViewScoped. Since we just want to show the technique of  firing one-time push when the web socket channel has been opened, we will not "pollute" the code and we will use the application scope.

Since this channel should "transport" a single message, we need to close the channel after receiving the first message, like below:

<div id="helloId"></div>

<script type="text/javascript">           
 function socketListener(message, channel, event) {               
  document.getElementById("helloId").innerHTML = message;           
  jsf.push.close("hello");
 }
</script>

Further, we have an application bean capable to push the message to hello channel:

@Named
@ApplicationScoped
public class PushBean implements Serializable {

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

 public void pushAction() {
  push.send("Hello world!");
 }
}

The only aspect that we didn't cover so far refers to pushing the message automatically when the channel has been opened. For this, we can use two server events:

CDI WebsocketEvent will be fired with @WebsocketEvent.Opened qualifier
This event is fired when a web socket channel has been opened.

CDI WebsocketEvent will be fired with @WebsocketEvent.Closed qualifier
This event is fired when a web socket channel has been closed.

Both events can be observed in an application scoped CDI bean as below. So, in our case we can take advantage of the event fired when the web socket channel has been opened and push the Hello world! message:

@ApplicationScoped
public class WebsocketObserver {
   
 private static final Logger LOG =  
                Logger.getLogger(WebsocketObserver.class.getName());       
   
 @Inject   
 private PushBean pushBean;

  public void onOpen(@Observes @Opened WebsocketEvent event) {        
  pushBean.pushAction();       
 }   
   
 public void onClose(@Observes @Closed WebsocketEvent event) {
  String channel = event.getChannel();
  LOG.log(Level.INFO, "Channel {0} was successfully closed!", channel);
 }
}

Notice that via the WebsocketEvent object we can obtain information such as:

Returns a string representing the <f:websocket/> channel name:
event.getChannel();         

Returns a string representing the <f:websocket/> user:
event.getUser();            


Returns a CloseCode instance representing the close reason code:
event.getCloseCode();      

Now, our application output will be like in figure below:


The complete application is available here.

Niciun comentariu:

Trimiteți un comentariu