The UI Engine is implemented as a multi-threaded server. A listener thread accepts connections from applications and creates Connection objects for each client. A thread in the Connection object receives requests from applications and posts them into an AWT event queue. Events and callbacks going back from the UI Engine to the application are put into a write queue of the associated Connection object and processed inside a separate writer thread (left hand side of Figure 1).
Figure 1: Internal Architecture of the UI Engine in Server Mode
The AWT main thread reads and processes events from the AWT event queue. These requests either create objects which are registered for later reference in the Connection's registry or they call
methods on already existing objects.
Since all manipulation of the widget tree is serialized no explicit synchronisation is necessary. Because callbacks from the UI to the application are never waiting for results synchronously, no blocking can occur in the main thread. Both design decisions simplify the architecture dramatically and improve its robustness.
The architecture of the application side of ULC is similar to the UI Engine side. Every application has a Connection object which handles asynchronous communication by means of two threads
and maintains the faceless halves of objects in a registry (right hand side of Figure 1).
The above architecture is based on the assumption that the UI Engine is running as a server process listening on a well known port and that different applications connect to that server.
In client mode the UI Engine and application are switching roles: the UI Engine becomes the client and connects to the application which runs in server mode (Figure 2). The listener thread now runs in the application server and accepts connections from UI Engines. For every connection a new connection object is created which establishes an independent context for running the application.
Figure 2: Internal Architecture of UI Engine in Client Mode
It is obvious that the architecture is very similar to the one depicted in Figure 1. In fact the connection objects are identical on both sides. The most important difference is that the application code runs in parallel inside a single address space. Therefore synchronization problems have to be addressed by protecting your data from concurrent access.