Как сделать redirect из другого потока используя JSF Primefaces?
У меня есть некий JSF компонент, хранящий состояние страницы специализаций. На этой странице пользователь выбирает специализацию, а затем ждёт действия со стороны другого пользователя. Так вот, если реализовать это последовательно, юзер зависнет на странице специализаций в бесконечном цикле, который будет проверять, совершено ли действие другим пользователем. Я хочу вынести это действие в другой поток для того чтобы юзер мог продолжать заниматься своими делами на странице, а когда бесконечный цикл в другом потоке завершится происходил редирект.
Проблема в том, что PrimeFacesContext не шарится между потоками (ThreadLocal). И запуская цикл в другом потоке я не могу совершить редирект средствами JSF, поскольку контекст - null.
Я в отдельном потоке запускаю цикл для проверки. И когда this.isAccepted(), пытаюсь делать редирект.
ThreadPoolHolder.addNewTask(() -> {
try {
while (true) {
if (this.isAccepted()) {
PrimeFacesContext.getCurrentInstance().getExternalContext().redirect("/serve");
break;
}
}
} catch (Exception exception) {
LOG.error("Ошибка в задаче thread pool");
}
});
Подскажите пожалуйста, как выйти из этой ситуации? Заранее всем спасибо за помощь.
Ответы (1 шт):
Проблема заключается в том, что объект PrimeFacesContext недоступен в другом потоке из-за использования ThreadLocal. Вместо использования отдельного потока для проверки состояния, вы можете использовать AJAX-запросы, чтобы проверять состояние на сервере и обновлять страницу клиента, когда состояние изменится.
Например, вы можете создать метод в управляемом бине, который проверяет состояние и возвращает результат в формате JSON. Затем вы можете использовать библиотеку JavaScript, например jQuery, чтобы отправлять AJAX-запросы на сервер с определенным интервалом и обновлять страницу, если состояние изменилось.
Примерный код на стороне сервера:
@ManagedBean
@ViewScoped
public class SpecializationBean implements Serializable {
private boolean accepted = false;
public void checkAccepted() {
// проверка состояния и установка флага accepted
}
public boolean isAccepted() {
return accepted;
}
public String getAcceptedAsJson() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("accepted", accepted);
return jsonObject.toString();
}
}
Примерный код на стороне клиента с использованием jQuery:
function checkAccepted() {
$.ajax({
url: "/checkAccepted",
dataType: "json",
success: function(result) {
if (result.accepted) {
window.location.href = "/serve";
} else {
setTimeout(checkAccepted, 1000); // повторить через 1 секунду
}
},
error: function(xhr, status, error) {
console.error(error);
setTimeout(checkAccepted, 1000); // повторить через 1 секунду
}
});
}
$(document).ready(function() {
checkAccepted(); // начать проверку при загрузке страницы
});
Здесь функция checkAccepted отправляет AJAX-запрос на сервер по адресу /checkAccepted и ожидает ответ в формате JSON. Если ответ указывает на принятие, то происходит перенаправление на страницу /serve. В противном случае функция вызывает саму себя через 1 секунду, чтобы повторить проверку через определенный интервал времени. Функция checkAccepted вызывается при загрузке страницы с помощью события ready объекта jQuery.