Skip to content

Client Server Protocol

Jan Koehnlein edited this page Jan 4, 2019 · 1 revision

This page describes the protocol between a sprotty client and its model source. A model source is configured by binding an implementation to TYPES.ModelSource, e.g. LocalModelSource for a client-only source or WebSocketDiagramServer for a server connected via web socket. Both approaches use the same protocol, so we will assume a remote server for the rest of this page for simplicity.

Layout Computation

The approach for computing model layouts has a strong influence on the client-server protocol, therefore we address this topic before going into more details on the protocol itself.

Both the client and the server may have their share in computing the layout. Usually the client is responsible for the micro layout, that is the positioning and size computation for labels and other elements that add visual information to composite elements such as nodes. The server, in turn, is responsible for the macro layout, that is the arrangement of the main model elements (e.g. nodes and edges) with the goal of optimizing visual clarity and readability. Macro layout computation depends on the results of micro layout computation, hence the client computes its layout before the server does. With the default settings, client layout is switched on and server layout is switched off.

Client Layout

In the client the layout approach is configured with the ViewerOptions:

overrideViewerOptions(container, {
    needsClientLayout: true,
    needsServerLayout: false
});

Client-side layouts are selected with the layout property of model elements that support this, such as SNode and SCompartment. hbox, vbox, and stack are built-in layout types that can be used here. The layout is computed in two phases:

  1. A RequestBoundsAction is received and the model is rendered invisibly, e.g. by assigning its containing DOM element a width and height of zero. The locally used fonts and CSS styles are applied during this hidden rendering phase. The resulting size information is used to invoke the selected layouts, and the updated bounds are written into a ComputedBoundsAction.
  2. The model source takes care of applying the bounds stored in the ComputedBoundsAction to the model, and then initiates the visible rendering of the updated model with a SetModelAction or UpdateModelAction.

Server Layout

On the server, the layout approach is configured on a DefaultDiagramServer instance:

diagramServer.setNeedsClientLayout(true);
diagramServer.setNeedsServerLayout(false);

The server-side layout is configured with an implementation of ILayoutEngine. Either bind it through dependency injection or set it directly on a DefaultDiagramServer instance. For graph-like models the ElkLayoutEngine can be used, which employs the Eclipse Layout Kernel (ELK).

If no client-side layout is necessary, the ILayoutEngine can be invoked directly after a new model is available. Otherwise the two-phase process explained above must be initiated, first triggering a hidden rendering and then invoking the server-side layout with the updated bounds.

Set and Update the Model

The primary purpose of the diagram server is to provide models. The protocol for setting or updating the model differs depending on how the layout is computed.

In the following, C → S denotes a message from the client to the server, and C ← S denotes a message from the server to the client.

A) No Layout Computation / Server-Only Layout

In this scenario, the server needs to provide a model with complete layout information, so no further processing by the client is required.

  • Client requests a model
    1. C → S: RequestModelAction
    2. C ← S: SetModelAction
  • Server updates the model
    1. C ← S: UpdateModelAction

B) Client-Only Layout

The server sends RequestBoundsAction to the client instead of updating the model directly. The client does not forward the resulting ComputedBoundsAction to the server because that would be an unnecessary round-trip. The updated bounds are applied locally in the client instead.

  • Client requests a model
    1. C → S: RequestModelAction
    2. C ← S: RequestBoundsAction
  • Server updates the model
    1. C ← S: RequestBoundsAction

C) Client and Server Layout

Same as scenario B), but here the ComputedBoundsAction is processed on the server so it can apply its own layout engine to the updated model.

  • Client requests a model
    1. C → S: RequestModelAction
    2. C ← S: RequestBoundsAction
    3. C → S: ComputedBoundsAction
    4. C ← S: UpdateModelAction
  • Server updates the model
    1. C ← S: RequestBoundsAction
    2. C → S: ComputedBoundsAction
    3. C ← S: UpdateModelAction

Show and Hide Popups

Usually popups are shown when the user hovers the mouse cursor over an element, and they are hidden when the cursor leaves the element. The server might also show and hide popups spontaneously by sending a SetPopupModelAction. An existing popup is hidden by setting a new popup model with NONE as root element type.

  • Client requests a hover popup
    1. C → S: RequestPopupModelAction
    2. C ← S: SetPopupModelAction
  • Server updates the popup spontaneously
    1. C ← S: SetPopupModelAction

Change Selection

Usually the selection is changed by the user by clicking on model elements. The server might also manipulate the selection spontaneously by sending a SelectAction.

  • Client notifies about changed selection
    1. C → S: SelectAction
  • Server changes the selection spontaneously
    1. C ← S: SelectAction