I have a JavaFX 8 application. It uses kind of observer pattern to react to events:
public class EventBus {
public static final EventBus INSTANCE = new EventBus();
private final Set<EventListener> listeners;
private EventBus() {
listeners = new HashSet<>();
}
public void register(EventListener listener) {
listeners.add(listener);
}
public void fire(Event event) {
listeners.forEach(listener -> listener.eventFired(event));
}
}
It worked pretty well so far for all my usecases:
- Interaction with buttons
- Events from external controllers, which I observe with
Platform.runLater()
initiated thread - etc.
Now I want to start embedded Undertow HTTP server and deploy a JAX-RS endpoint inside. Whenever a request comes in there, I want to fire an event from within that endpoint using the above event bus. So, this is how I start Undertow and deploy my JAX-RS app:
UndertowJaxrsServer server = new UndertowJaxrsServer().start();
server.deploy(new MyEndpoint(eventBus));
The thing is that new UndertowJaxrsServer().start()
is asynchronous call and it starts a thread of itself. And then when MyEndpoint
handles a request and tries to fire an event, it happens from that thread, which was started by Undertow.
So in the event listener, if I try to do any updates on the UI, I get:
java.lang.IllegalStateException: Not on FX application thread; currentThread = XNIO-1 task-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.clear(VetoableListDecorator.java:294)
at ui.DialogManager.showDialog(DialogManager.java:109)
Finally, my question is is there a way to explicitly tell JavaFX to run a piece of code in the UI thread, even if the call stack comes from another one (to which I do not have control and on which I can't do Platform.runLater()
).
Thanks!