Al-un
Al-un

Reputation: 3422

Omnifaces socket + commandScript combinations

I'd like to implement the OmniFaces <o:socket> with the <o:commandScript> option as documented here.

My JSF page looks like:

<h:form id="myForm">
    <!-- the socket is by default disconnected. It will
         connect when the user selects a subChannel. 
         Setting the subChannel to "null" must disconnect
         the socket -->
    <o:socket channel="myChannel" scope="session"
              connected="#{myManager.subChannel ne null}"
              user="#{myManager.subChannel}"
              onmessage="someTestScript" onopen="onOpen" onclose="onClose"/>

    <o:commandScript name="someTestScript"
                     actionListener="#{myManager.testPush}"
                     render=":testValue" />

    <!-- dummy rendering to check if everything is working -->
    <h:panelGroup id="testValue"
                  rendered="#{myManager.subChannel ne null}" >
        <h:outputText value="#{myManager.bbb} #{myManager.aaa}" />
    </h:panelGroup>

    <!-- To simplify: I have several buttons which allows
         the user to select the socket "user". The buttons
         are only displayed when no "user" is selected 
         (thus, socket is not connected yet as well) -->
    <p:dataGrid value=#{...a list...} var="sth" 
                rendered="#{myManager.subChannel eq null">

        <p:ajax event="click"
                update="myForm"
                listener="#{myManager.setSubChannel(sth.id)}" />

        <p:panel>
            <h:outputText value=#{sth.text} />
        </p:panel> 

    </p:dataGrid>

    <!-- Resetting -->
    <p:commandButton value="Reset"
                     actionListener="#{myManager.setSubChannel(null)"
                     update="myForm" />
</h:form>

My backing bean:

@Named(value = "myManager")
@SessionScoped
public class MyStuffManager implements Serializable{

    private Long subChannel = null;
    private Long aaa;
    private String bbb;

    public void testPush(Long aaa, String bbb){
       System.out.println("Text received: " + bbb + ", Number received: " + aaa);
       this.aaa = aaa;    
       this.bbb = bbb;
    }

    // getter & setter

}

My socket push point:

@Named 
@ApplicationScoped
public Class mySocket implements Serializable{
    @Inject
    @Push(channel = "myChannel")
    private PushContext socket;

    // Basically, all methods are triggered by CDI events. So
    // far, I just want to send an int and a String to see how
    // I send parameters.
    public void test(@Observes @MyEventQualifier AnEvent event) {
        Map<String, Object> input = new HashMap<>();
        input.put("aaa", 123456789);
        input.put("bbb", "a text");
        socket.send(input);
    }
}

Currently, my situation is:

  1. When clicking a panel and the "reset" button, the socket properly connects and disconnect.
  2. Still according to linked documentation, the <f:ajax> option properly works but I cannot send parameters.

However, my open points are:

  1. the <o:socket> has a "null" user attribute. Regardless if I use the "connect" attribute to trigger a connection or a
    oncomplete="OmniFaces.Push.open('myChannel')"
    , the subChannel is still resolved to null. Strangely enough, if I execute other JSF stuff (like updating an <h:outputText> field), the subChannel is properly updated and retrieved. How should I have a dynamic "user" attribute depending on a EL when connection is not automatic?
  2. I have missed something from the OmniFaces documentation as the myManager.testPush is never called. What have I missed? Instead, I have a ReferenceError: someTestScript is not defined on my Firefox console. I tried to add an empty someTestScript in a JavaScript file but it looks like only the empty one is called, not the o:commandScript.

We're using OmniFaces 2.6 as stated by the documentation.

Any hint/advise is obviously welcomed. Thanks.

Upvotes: 2

Views: 1038

Answers (1)

Al-un
Al-un

Reputation: 3422

I finally fixed it! For those who are interested in the solving, and note for myself later:

1) How to dynamically change sub channel

Option 1: Change the o:socket scope to view so that the HTTP session scope is wider than the socket scope.

<o:socket channel="myChannel" scope="view"
          connected="#{myManager.subChannel ne null}"
          user="#{myManager.subChannel}"
          onmessage="someTestScript" onopen="onOpen" onclose="onClose"/>

When exiting the socket, the socket will properly closes and re-open with the correct subChannel value. For some reasons, it seems than having a "subChannel" as a String works better than Long.

Option 2: Use a "sub channel map". Actually, I haven't stated in my problem than multiple users can connect to the same sub channel. Another option is to have all users connected via their userId <o:socket channel="myChannel" user="#{user.id}" session="scope" /*default value anyway*/ {...}/>

Then, instead of sending to a subchannel, I send to a collection of user id:

Map<String, Set<String>> subChannelUserMap = new HashMap<>();
// ...
public void onUserConnect(User user, String subChannel){
    subChannelUserMap.get(subChannel).add(user.getId());
}
// ....
public void sendMessage(Map<K, V> input, String subChannel){
    socket.send(input, subChannelUserMap.get(subChannel));
}

2) Call backing bean methods from JavaScript

As stated in my self-comment, I misunderstood <o:commandScript> usage. Let's consider the backing bean method:

// ...
public class BackingBean{
    public void test(){
        String aaa = Faces.getRequestParameter("aaa", String.class);
        String bbb = Faces.getRequestParameter("aSillyName", String.class);
        LOGGER.debug("aaa={}, bbb={}", aaa, bbb);
    }    
}

with the socket written as <o:socket /*...*/ onmessage=onMessage />, I'll have:

JSF Page:

 <o:commandScript name="aSillyFunctionName" render="..." 
                  actionListener="#{backingBean.test}" ... />

JavaScript file:

 function onMessage(message, channel, event){
     aSillyFunctionName({aaa: message.aaa, aSillyName: bbb});
 }

And here I'm done.

Upvotes: 2

Related Questions