Инициированный сервером рендеринг: EJB -> FacesContext?

Я уже задавал этот вопрос на форуме Icefaces, но пока понял, что это более общая проблема.

Я хотел бы обновить части страницы JSF, когда я получаю сообщение в своей MDB.

Проблема в том, как мне получить FacesContext из контейнера EJB?

В функции обработки сообщений FacesContext.getCurrentInstance() возвращает null.

Я также пытался сделать управляемый компонент JSF MDB, но не смог (похоже, вы не можете иметь оба в одном классе?).

Поскольку я новичок в мире JSF, я сейчас застрял. Есть ли способ заставить его работать?

(Glassfish v3 + Netbeans 6.8, JSF2 + Icefaces 2.0 alpha2)


person egbokul    schedule 20.04.2010    source источник


Ответы (4)


FacesContext основан на HTTP-запросе и поэтому доступен только во время обработки HTTP-запроса и даже тогда, когда URL-адрес запроса соответствует шаблону URL-адреса FacesServlet. Если вы не находитесь внутри потока, который выполняется сервером для обработки HTTP-запроса, то также нет средств FacesContext. В контейнере EJB полностью отсутствуют HTTP-запросы.

Технически, единственный способ позволить EJB информировать JSF о новом сообщении — позволить EJB запустить HTTP-запрос по URL-адресу, соответствующему шаблону URL-адреса FacesServlet с сообщением в качестве параметра запроса. Вы можете использовать java.net.URLConnection для этого. JSF, в свою очередь, может затем выполнить push-уведомление Comet/HTTP, чтобы обновить представление с помощью сообщения IceFaces, как вы упомянули.

E.g.

URL url = new URL("http://example.com/context/poll.jsf?msg=" + URLEncoder(msg, "UTF-8"));
URLConenction connection = url.openConnection();
InputStream response = connection.getInputStream();

и poll.jsf, который прикреплен к вспомогательному компоненту следующим образом:

@ManagedBean
public class Poll {

    @ManagedProperty(value="#{param.msg}")
    private String msg;

    @PostConstruct
    public void init() {
        // Do something with msg.
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

}

Примечание. Используются аннотации JSF 2.0, но они должны быть достаточно понятными.

person BalusC    schedule 20.04.2010
comment
Спасибо за ответ. Это работает, хотя, на мой взгляд, все еще не самое чистое решение (почему сервер приложений EE не имеет внутреннего способа сделать это без внешнего вызова сервлета?), но приемлемо. - person egbokul; 21.04.2010

Я не эксперт, но ожидаю, что FacesContext доступен только во время обработки запроса JSF. Я боюсь, что вы не можете делать именно то, что хотите, но вы, безусловно, можете обойти это. На самом деле есть две проблемы:

  1. Как получить обновление через MDB на страницу JSF?
  2. Как обновить страницу на клиенте при возникновении события? Обычно вы не можете отправлять данные с сервера клиенту, клиент должен их запросить (хотя есть некоторые обходные пути, такие как http://en.wikipedia.org/wiki/Comet_(programming)))

Я хотел бы что-то вроде следующего:

  1. В MDB сохраните обновленные данные где-нибудь, например, в глобальном кеше (сессионный компонент без сохранения состояния с @Singleton и коллекцией или картой для обновлений)
  2. Измените страницу JSF, чтобы она запрашивала у сервера обновления через регулярные промежутки времени (предпочтительно в фоновом режиме с использованием Ajax через какой-либо компонент JSF с поддержкой ajax) — если есть обновление, полученное через MDB, сервер вернет его, и страница будет перерисовать себя
person Jakub Holý    schedule 20.04.2010
comment
Привет, спасибо за ответ. № 2 прост, потому что в Icefaces 2.0 есть свой класс PushRenderer, который хорошо работает. # 1 - это вопрос: как мне обратиться к экземпляру класса, управляемому FacesServlet, если я нахожусь за его пределами? EJB запускаются в другом контейнере... - person egbokul; 20.04.2010
comment
@egbokul #1 вообще не работает с JSF, он просто хранит данные в сеансовом компоненте @Singleton, к которому затем может получить доступ JSF. Так что это JSF -> EJB, а не наоборот. Но с помощью PortableRenderer, о котором вы упомянули, вы, надеюсь, сможете передать данные из MDB прямо в JSF. Мне любопытно, как это работает :-) Удачи! - person Jakub Holý; 22.04.2010

У меня есть обходной путь, который включает таймер на стороне JSF (к счастью, он только на сервере, нет необходимости в AJAX и клиент-серверной связи), который проверяет Singleton и при необходимости запускает обновления. Однако я все еще считаю, что это не правильное решение и что это можно сделать без таймера...

person egbokul    schedule 20.04.2010

Я также получил ответ на форуме Icefaces:

org.icefaces.application.PortableRenderer предоставляет объект, который можно использовать в потоках, отличных от JSF, для вызова push-уведомлений. (Это доступно в транке svn и будет предоставлено в следующей альфа-версии (= Icefaces 2.0 alpha 3).)

person egbokul    schedule 21.04.2010