Sirius Architecture and Concepts

  1. Sirius Architecture and Concepts
    1. Introduction
    2. Sessions
      1. Transactional Editing Domain
      2. Changing the Viewpoint Selection
    3. Editing Sessions
    4. The Model Accessor
    5. Dialects
    6. The Viewpoint Registry

Introduction

This document presents an overview of the internal architecture of Sirius, and the main concepts and APIs.

Sirius relies heavily on the Eclipse platform, and reuses (and extends) many of the standard Eclipse frameworks, in particular the Eclipse Modeling Platform. This document assumes that you are already familiar with these frameworks and libraries, in particular EMF and EMF Transaction, GEF and GMF for diagrams. Refer to these frameworks' own documentation for more details about them.

Sessions

The central concept of Sirius’s API is the Session. In Sirius, all data is stored in EMF models: the semantic models themselves obviously, but also the representations (diagrams, tables) and the viewpoint configuration (the Viewpoint Specification Models). A session is a wrapper around a Transactional Editing Domain and its Resource Set. It ensures the consistency of the models inside the editing domain, from the platform’s point of view; for example it makes sure the representation files correctly reference all the semantic models they need to in order to handle the representations in the session. The session also provides high-level, Sirius-specific services through its own APIs and support classes and interfaces.

In the standard UI, each Modeling Project corresponds to exactly one Session, and each session contains its own Editing Domain and Resource Set. This means that sessions (and thus modeling projects) are isolated from each other.

The representation files ( *.aird files) can be though as the serialized form of a Session, and symmetrically a session is the runtime incarnation of a representation file (or more precisely of the unique top-level representation file in a modeling project).

A session, inside its resource set, contains three kinds of resources:

The SessionManager is a global object which references all the sessions currently opened in the system. It can also be used to find which session is responsible for a given semantic element. This is very important because many Sirius APIs require that you provide a Session parameter. If what you have is an element from a user semantic model, you can use SessionManager.INSTANCE.getSession(theSemanticElement) to find in which of the opened session, if any, this object is loaded. Note that this method can be relatively costly, so do not call it in tight loops to avoid hurting performance.

To create a Session programmatically:

URI sessionResourceURI = URI.createPlatformResourceURI("/Project/archi.aird", true);
Session createdSession = SessionManager.INSTANCE.getSession(sessionResourceURI);
createdSession.open();

The Session API provides several methods to manage the different kind of resources it contains: finding all the semantic resources and adding new ones, finding about all the referenced session resources (all the secondary *.aird files which are part of the same session), etc. Refer to the Session interface’s JavaDoc for details.

The Session.getInterpreter() method can be used to obtain an IInterpreter properly configured to query the models in that session. The interpreter it returns will handle expression from any of the supported query languages, and you can use it to run your own queries (see the IInterpreter API).

Another interesting method in Session is Session.getEventBroker(). It returns a SessionEventBroker object, which can be used to add trigger actions that will be performed whenever a change in the session’s model occurs. See SessionEventBroker and ModelChangeTrigger for details.

When you are finished working with a session, you must close() it. This will unload all the models in its resource set and free the corresponding memory. After a session has been close it can not be reopened, but you can open a new one on the same files if needed.

Transactional Editing Domain

The editing domain associated to each session is an EMFT Transactional Editing Domain. In addition to basic undo/redo, it supports advanced features like atomicity and pre- and post-commit listeners, which are triggered after a command has been executed, and can be used to perform additional work (for pre-commit listeners) or to update external application data like UI state for post-commit listeners.

The Session.getTransactionalEditingDomain() will return the TransactionlEditingDomain for a session.

To modify a model element with a transactional editing domain, you must use a RecordingCommand. If you try to modify the models inside a session (semantic model or representations) outside the context of a recording command, you will get an exception. The proper usage pattern is:

TransactionalEditingDomain ted = ...;
ted.getCommandStack().execute(myCommand);

where myCommand is a RecordingCommand.

Changing the Viewpoint Selection

Each session has its own set of Viewpoints enabled, which determine which representations and extension are available. Users can change that selection using the Viewpoint Selection action (for example on a Modeling Project). You can also change this selection programmatically.

The simplest way to do this is to use the UserSession API; for example:

Session userSession = UserSession.from(createdSession);
userSession.selectViewpoint("Design");

Editing Sessions

An editing session, represented by an instance of org.eclipse.sirius.ui.business.api.session.IEditingSession, manages the graphical editors associated to a session. A session can exist without an associated editing session, but some operations require that an editing session is explicitly opened. At most one editing session can exist for a given session.

To retrieve the editing session associated to a session or create a new one, use the org.eclipse.sirius.ui.business.api.session.SessionUIManager API. The manager serves both as a factory for editing sessions and as a registry of all the ones which are opened at a given time and which session they correspond to.

The main services offered by an editing session are to open, close, save, and generally manage the lifecycle of the Eclipse editors associated with a session. Every time a representation (e.g. a diagram) is opened on a model, it happens through the corresponding editing session.

You can use the editing session’s APIs yourself to open representations, check their dirty states, save them, etc. Refer to the EditingSession's JavaDoc for details.

You can also register IEditingSessionListeners on an editing session, to be notified of state changes in the session, in particular when it becomes dirty, meaning that it contains unsaved changes.

The Model Accessor

The semantic models inside a session are never manipulated directly by Sirius. All access to these models is mediated through the session’s ModelAccessor instead of directly through the normal EMF reflective APIs. This accessor serves two purposes:

You can obtain the model accessor associated to a session using the Session.getModelAccessor() method, and the permission authority using ModelAccessor.getPermissionAuthority(). If you extend Sirius, you should make sure to use the model accessor API to read and write the semantic model, and to use the permission authority to check any change you want to perform beforehand.

Dialects

Sirius supports different kinds of representations: diagrams, tables and trees. These are all dialects, which are supported by default by the platform. The core of the platform only deals with the abstract notion of a dialect, and each one is simply an extension.

The DialectManager ( org.eclipse.sirius.business.api.dialect.DialectManager) offers some general APIs which can be used to manipulate representations in a uniform way, independently of which concrete dialect provides them. The DialectManager can be used to:

The DialectManager is a global object but the services it offers work on representations inside sessions, so all the methods it provides require a Session object as argument.

In the same way as sessions are split in a core Session API and an EditingSession API to handle UI-specific services, the DialectManager is complemented with the DialectUIManager ( org.eclipse.sirius.ui.business.api.dialect.DialectUIManager), which offers generic APIs to representations services which depend on the UI. The main ones are:

The Viewpoint Registry

The ViewpointRegistry is a global object which knows about all the Viewpoint definitions available in the system at every time.

When a plug-in containing properly packaged VSMs is deployed, the registry will be notified (through the org.eclipse.sirius.componentization extension point) and register all the viewpoints defined in any of these VSMs. The registry also listens to changes in the Eclipse workspace to detect the creation, modification and deletion of any *.odesign files; this is (part of) what enables dynamic development of VSMs, with no need for a costly deployment of plug-ins to test your changes: the latest version of a Viewpoint definition from the workspace is always known from the registry.

You can use the registry to discover about all the viewpoint definitions which are available, and introspect the corresponding models. However be aware that the Viewpoint registry maintains its own editing domain and EMF ResourceSet in which the viewpoints are loaded. The model loaded in the registry are not the same as the ones loaded in a session that uses a given viewpoint. It is a different instance of the same model. This means you must be careful when comparing or passing around elements from a viewpoint definition. For example if you have defined a viewpoint named A, and have two different sessions where A is enabled, you will have three equivalent but different instances of A: one in each of the sessions' ResourceSet, and one in the ViewpointRegistry's private ResourceSet.

You can register listeners on the ViewpointRegistry to be notified when Viewpoints are registered, unregistered, or when the definition of a viewpoint changes (for example because it was defined from an *.odesign file in the workspace that you have just modified, and the registry detected it and reloaded the new definition);