The view is very thin and dumb and only shows what presenter tells it to. Presenter listens to UI events from the view, updates the model based on them, listens to model update events, and reads view state and updates view state.
I'm now searching for a good practise for handling EDT-threading problem. The model is inherently multithreaded in the sense that we have several threads running concurrently. They for example fetch data from different sources and update the model accordingly. An event is created, presenter listens to it and updates the view.
There's also operations that the user initiates. Those start in EDT, presenter does some actions on the model and possibly updates the view state as a result. If the action is fast, the whole thing can be done in EDT. If the operation takes a long time, the processing needs to jump out of EDT at some point to not block the UI.
When thinking about the events that are created from model due to some background thread, where should we jump back to EDT? There's options:
a) jump to EDT when presenter updates the view
view (EDT) <- presenter (either EDT or other thread) <- model (either EDT or other thread)
b) jump to EDT when moving to presenter layer
view (EDT) <- presenter (EDT) <- model (either EDT or other thread)
- could be implemented by creating an AOP aspect for all View interfaces(?) The aspect would jump to EDT if not there yet always when any method of the interface is called
- if one ModelEvent is received in non-EDT thread in Presenter, and 15 different View setters need to be called to update the view state, causes 15 separate SwingUtilities.invokeLater() calls...problem?
- model events and eventlisteners are straight forward to implement. Presenter and model do not need to be aware of Swing (existence of event dispatch thread)
- Presenter is multithreaded and presenter objects need to be implemented so that threading problems do not occur
- could be implemented for example by creating special model EventListener implementations that jump back to EDT when event is received
- model events and eventlisteners are not as straightforward to do as with a). Somewhere the events need to jump to EDT (event source or listener) and you cannot code just "simple plain" listeners and event sources
- Presenter needs to be aware of Swing (existence of event dispatch thread and need to jump back to it when events come from model) at least in the sense that it uses the correct EventListener implementations
- View interface could still check that thread = EDT when methods are called (using similar AOP) to ensure threading rules are not broken
- Presenter can be single threaded (always in EDT) and presenter implementer does not need to worry as much about threading
- note that above point requires that user-initiated long running operations, that can't be run in EDT, need to jump from EDT the model layer. If view initiates new non-EDT threads (for example using SwingWorker), Presenter still does have multiple threads running on it (although only "one way", from view to model) and needs to be made threadsafe. This is starting to sound bad, but even if Presenter is single threaded only "one way", it may still be easier to implement than presenter that is completely multithreaded?
I think major point in deciding is the difficulty of creating thread safe Presenters. Thread safe code is notoriously difficult to implement and even things that seem trivial at first sight can cause big problems. I can't help thinking that since the application's core is already multithreaded by nature, how much more difficult can it be to make the Presenters thread safe as well? Presenters should be quite simple in any case, can receiving events from model and calling a few setters on the view cause threading problems?
Note that this problem is not limited to programs where background threads update the data....any program where some long running operations are run outside of EDT, and may cause events that are listened to in some presenter, has to solve this issue.