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.
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:
aird
file(s), and contain representation data (e.g. diagrams);
*.odesign
files, and are typically loaded from installed plug-in instead of from the workspace (except when using the
dynamic mode to develop viewpoints).
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.
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
.
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 to this is to use the
UserSession
API; for example:
Session userSession = UserSession.from(createdSession);
userSession.selectViewpoint("Design");
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 opened by an editing session is 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 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:
IPermissionAuthorithy
. The permission authority is used to lock model elements (both diagram and semantic elements), and to check if you have read and/or write access to each element and feature before access or modification.
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.
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
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);