Комбинации сокетов и командных скриптов

Я хотел бы реализовать OmniFaces с параметром , как описано здесь.

Моя страница JSF выглядит так:

<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>

Мой боб:

@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

}

Моя точка нажатия розетки:

@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);
    }
}

В настоящее время моя ситуация такова:

  1. При нажатии на панель и кнопку "сброс", розетка правильно подключается и отключается.
  2. Тем не менее, согласно связанной документации, опция работает правильно, но я не могу отправить параметры.

Тем не менее, мои открытые позиции:

  1. имеет нулевой атрибут пользователя. Независимо от того, использую ли я атрибут "connect" для запуска соединения или
     OnComplete="OmniFaces.Push.open('мой канал')" 
    , подканал все еще разрешен к нулю. Как ни странно, если я выполняю другие вещи JSF (например, обновляя поле ), подканал корректно обновляется и извлекается. Как я должен иметь динамический атрибут "пользователь" в зависимости от EL, когда соединение не является автоматическим?
  2. Я что-то упустил из документации OmniFaces, так как myManager.testPush никогда не вызывается. Что я пропустил? Вместо этого у меня есть ReferenceError: someTestScript не определен на моей консоли Firefox. Я попытался добавить пустой someTestScript в файл JavaScript, но похоже, что вызывается только пустой, а не o: commandScript.

Мы используем OmniFaces 2.6, как указано в документации.

Любая подсказка / совет явно приветствуется. Благодарю.

1 ответ

Решение

Я наконец исправил это! Для тех, кто заинтересован в решении, и обратите внимание на себя позже:

1) Как динамически менять подканал

Вариант 1. Измените область просмотра o: сокета, чтобы область сеанса HTTP была шире, чем область сокета.

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

При выходе из сокета сокет должным образом закрывается и снова открывается с правильным значением subChannel. По некоторым причинам кажется, что наличие "подканала" в качестве строки работает лучше, чем Long.

Вариант 2: используйте "карту подканала". На самом деле, я не указал в своей проблеме, что несколько пользователей могут подключаться к одному и тому же подканалу. Другой вариант - подключить всех пользователей через их userId. <o:socket channel="myChannel" user="#{user.id}" session="scope" /*default value anyway*/ {...}/>

Затем, вместо отправки в подканал, я отправляю в коллекцию идентификатор пользователя:

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) Вызов методов бина поддержки из JavaScript

Как сказано в моем комментарии, я неправильно понял <o:commandScript> использование. Давайте рассмотрим метод поддерживающего бина:

// ...
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);
    }    
}

с сокетом, написанным как <o:socket /*...*/ onmessage=onMessage />, У меня будет:

Страница JSF:

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

Файл JavaScript:

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

И вот я закончил.

Другие вопросы по тегам