Model services

Modelio v3

Modelio API model services are used to manipulate the model of the currently opened project.

Quick outline:

  1. IModelingSession
  2. Model API naming rules
  3. Transactions
  4. Creating and deleting elements
  5. Listening to model changes

IModelingSession

The IModelingSession object provided by Modelio to the module represents the very core access point to the model. A modeling session is a transaction-based access to the model contained in the currently opened project. Without a valid modeling session you have neither read nor write access to the model.

A modeling session can be opened or closed. A closed session is useless as it does not provide more help than no session at all. An opened session is really what you need to work with the model. Note that,however, a “closing-in-progress” session might be useful as it can mean that it is time to stop certain activities of your module or to free some resources and so on.

For now let us stick to simple principles, Modelio can provide you with a valid modeling session using the following code:

1IModelingSession session = Modelio.getInstance().getModelingSession();

And if you ask what happens when there is no current valid session?

the answer is straightforward getModelingSession() just returns a null object.

Does it mean that you’ll have to check the returned value of getModelingSession() each time you call it?

no, a properly designed module can never fall in such a situation where its code is running without a valid session being available. See Modules core concepts to understand how this magic is possible.

Model API Naming rules

The so-called Model API is the set of Java classes and methods that represent the model elements.

The Model API Java classes and their methods follow some fixed naming rules that help a lot in identifying which object and which methods to use to navigate in the model. So it is worth spending a little time on these naming rules, the alternative would be to browse and learn the complete Model API classes and methods from the Java documentation… more than 250 classes and 3000 methods. Go for the naming rules!

Metaclass representation

For each metaclass of the Modelio metamodel, a corresponding Java interface is defined. It is simply named from the Modelio metaclass. The metamodel inheritance graph between metaclasses is cloned at the Model level.

The following table provides several examples.

Modelio metaclass nameModelio parent metaclassJava interfaceJava parent interface
OperationBehavioralFeatureOperationBehavioralFeature
ClassGeneralClassClassGeneralClass
UseCaseGeneralClassUseCaseGeneralClass
xxxxyyyyxxxxyyyy

Associations and Attributes methods

The model API provides direct access to attributes and associations in the metamodel in the form of accessor methods or accessors. Accessors that are used to read the model are called setters while accessors that modify the model are called getters.

As for metaclasses, the model API has been designed so that accessors names directly relate to the navigated attributes or associations thereby making it easy to guess the name of the concrete accessors of any attribute or association from a quick look to the metamodel diagrams.

The following table shows the prefixing rules for a association role or an attribute named XXX.

AccessorCardinalityPrefix rule
Getter 1getXXX() or isXXX() for a boolean
Getter *getXXX()
Setter 1setXXX()
Setter *getXXX().add() and getXXX().remove()

Get a general description of the accessor naming rules usage see here.
Watch the accessor naming rules in action on concrete examples here.

Transactions

Modelio Transactions:

  • are required to modify the model: no modification of the model can be carried out without being encapsulated within a Transaction.
  • have to be committed for the modification to take place: changes in the model are only effective after a transaction has been successfully committed).
  • can be rolled back, leaving the model unchanged up to its state when starting the transaction

Any modification of the model made outside any transaction will throw an exception.

Transactions guarantee that the modifications of the model follow the ACID paradigm. ACID is an acronym for Atomic, Consistent, Isolation, and Durable.

Atomicity

A transaction allows for the grouping of one or more changes in the model to form an atomic or indivisible operation. In other words, either all of the changes occur or none of them do. If for any reason the transaction cannot be completed, everything this transaction changed can be restored to the state it was in prior to the start of the transaction, via a rollback operation.

Consistency

Transactions always operate on a correct model and when they end always leave the model in a correct state. The model is said to be correct as long as the Modelio audit system does not return blocking errors for it. During a transaction, the model may be incorrect at some point, however no other transaction will be allowed to see these inconsistencies, and all such inconsistencies will have been eliminated by the time the transaction ends.

Isolation

To a given transaction, it should appear as though it is running all by itself on the model. In Modelio, there is only one active transaction at a time. Such a unique transaction is de facto isolated.

Durability

Once a transaction is committed, its effects become definitive, ie they are definitively applied to the model. As long as the transaction is not committed, the modifications can be rolled back to restore the model to its initial state.

Transactions API

The transaction management API is available from the IModelingSession object. More details on the transaction API here.

Transactions and Audit

Modelio constantly monitors the model for correctness by running an Audit.

Some of the controls carried out by the audit are blocking, ie they cannot fail without breaking the model. These strong inconsistencies are always controlled by Modelio in real-time each time a transaction is committed. This is why committing a transaction can fail, the changes can simply NOT be carried out by the tool without leading to serious troubles (including tool crashing in the worst cases). Modelio will throw an exception at any model modification out of a transaction because it needs this final check at commit time to ensure its own integrity.

Creating and deleting model elements

To create a model element, the modeling session provides a model element creation factory IUmlModel. The model element factory provides many creation methods, listing them all would be useless.

Just have a look to a code fragment:

1// get the modeling session
2IModelingSession session = Modelio.getInstance().getModelingSession();
3
4// get the factory
5IUmlModel factory = session.getModel();
6
7// use the factory to create elements, here a simple class
8Class newClass = factory.createClass();

A complete and explained example is visible here.

IMPORTANT WARNINGS

  • Using the factory is the unique operational means of creating new model elements.
  • do not attempt to modify the model outside an opened transaction.
  • do not use the Java new operator to create new elements in the model as this would not work at all and lead to errors.

Deleting elements

In order to delete an element, simply call its delete method.

Example: deleting all the classes under the root package

 1IModelingSession session = Modelio.getInstance().getModelingSession();
 2
 3try (ITransaction t = session.createTransaction("Delete all root classes");) {
 4    // Get all work model roots
 5    for (MObject rootObj : session.getModel().getModelRoots() ) {
 6        // Looks for a Project instance
 7        if (rootObj instanceof Project) {
 8            // Get the model root package
 9            Package root = ((Project) rootObj).getModel();
10
11            // Get the root children classes
12            List<org.modelio.metamodel.uml.statik.Class> ownedClasses = root.getOwnedElement(org.modelio.metamodel.uml.statik.Class.class);
13
14            // Loop on classes under root
15            for (org.modelio.metamodel.uml.statik.Class clazz : new ArrayList<>(ownedClasses )) {
16                // Delete the class
17                clazz.delete();
18            }
19        }
20      }
21
22    // commit the transaction 
23    t.commit();
24}
25
  • line 3 – this construction known as ‘try with resources’ will guarantees that the transaction will be properly closed in any circumstances (uncaught or unplanned exceptions occuring)
  • line 5, 7 – iterates the Modelio project work models to get the root Project instances.
  • line 12 – the use of the filtered getter accessor getOwnedElement(org.modelio.metamodel.uml.statik.Class.class) will return only the classes under root. A fully namespaced class name is used to avoid any confusion with other classes like java.lang.Class and so on.
  • line 15 – as ‘delete’ modifies the list content, it is necessary to loop on a copy.
  • line 17 – the deletion of the class is done on line 17 but will only become effective after the commit on line 23.
  • line 24 – if an uncaught exception occurs, this closing brace will automatically rollback and close the transaction created on line 3. Of course, this does not happen when everything is successful and when the transaction is sucessfully committed (line 23).

Listening to model changes

The Modeling session can register so-called ‘model listeners’. A model listener is any object implementing the IModelChangeListener interface. Registered model listeners are called when a change is committed in the model and a IModelChangeEvent object describing the changes is passed to them. Model change listeners can, for example, be used to update views displaying model elements or any information that depends on model elements.

 1IModelingSession session = Modelio.getInstance().getModelingSession();
 2
 3// register a IModelChangeListener
 4
 5session.addModelListener(new IModelChangeListener() {
 6    public void modelChanged(IModelingSession session, IModelChangeEvent event) {
 7        System.out.println("model changed");    
 8    }
 9});

The above code fragment registers a IModelChangeListener that simply prints out a message whenever the model is modified (see about using System.out). Of course by exploiting the passed IModelChangeEvent more advanced behavior can be implemented. More complete details about model change listening is available here.

Tip

You can remove a model change listener by

1    session.removeModelListener(myListener)


but this supposes that you have previously kept a reference to your listener.