Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Papyrus-RT/Developer/Design/0.9/UML-RT-Implementation

< Papyrus-RT‎ | Developer‎ | Design
Revision as of 13:40, 4 January 2017 by Give.a.damus.gmail.com (Talk | contribs) (Link to protocol inheritance demo)

UML-RT Semantics in Eclipse UML

This document describes the implementation of UML-RT semantics in Papyrus as a customization of the Eclipse UML2 implementation of UML.

Most of the APIs and other code described herein are implemented in a new bundle org.eclipse.papyrusrt.umlrt.uml. Critically, this bundle is designed (and required) to operate in a "pure Java" context, that is, without the Eclipse or any OSGi run-time running. Changes in other bundles are required to integrate these into Papyrus-RT; those will be called out in the text below.

Development of this feature is tracked in bug 467545, with attendant git branches, Gerrit patches, and blocking/related bugs. Builds of the feature branch are produced here. Use caution when trying these builds! Do not use them on models that you care about without adequate backup. There are bugs, particularly in undo/redo, which usually is intended to provide a safeguard.

Demonstrative videos are posted from time to time on YouTube:

Incremental Redefinition

The key concept in UML-RT that distinguishes it, besides the profile, from UML is the notion of incremental redefinition. This recognizes that a redefining element can leave some of its attributes unset so that they shall be interpreted as being inherited from the redefined element. This is accomplished by means of subclasses of the UML2 implementation classes for the various redefinable elements. These implement an internal interface InternalUMLRTElement that defines various operations for inheriting values of unset features from the redefined element, setting the redefined element, and more. The custom implementation classes use these common internal APIs to override the basic UML features inherited from Eclipse UML2.

UML-RT Implementation Classes

These custom implementation classes also override the methods implementing standard UML well-formedness constraints to account for UML-RT requirements, especially for type compatibility in protocols, connector ends, etc.

Stand-alone Configuration

For configuration of a ResourceSet to work with UML-RT models, a static utility class UMLRTResourcesUtil is provided as an analogue to UMLResourcesUtil from the UML2 API (the former actually uses the latter for core UML set-up). The init(ResourceSet) API performs all of the registrations required to install the UML-RT support described in this document in a resource set.

UML Extensions

When a generalization relationship is established between capsules or protocols, or a redefinition relationship between state machines, then inheritance of elements is activated that is managed in part by extensions to the UML metamodel. These essentially are structural features of model elements that are stored in separate companion objects (extensions) made accessible through the elements, themselves. So, in a sense they are like features that may be added to metaclasses by package merge, only there is no actual merge; but in practice they are much more like stereotypes, except that they are more deeply integrated into the elements by way of the custom implementation classes.

The extensions are modelled as a metamodel umlext with metaclasses that mirror the extended metaclasses in name and generalization relationships. One important use case for the extensions is to store implicit redefinitions of inherited elements for the cases where they are neither excluded nor configured differently in any attribute as compared to the inherited element. These implicit redefinitions are stored in extension attributes as depicted in the diagram below. The implementation classes, for example ClassImpl, are instrumented to forward access to these features via Ecore reflection to the extension object. This makes it possible, for example, to extend the ownedMember superset in the ClassImpl to include the implicitAttribute and implicitConnector properties. This ripples to other derived unions such as ownedElement.

UML Extensions

The extension elements are stored in a special resource maintained in the resource set, called the extension extent. This resource, therefore, indirectly contains any "virtual elements" that are these implicit members or other model content. It also maintains an adapter on every element contained within it that, when some concrete change is made to it (thus effecting an incremental redefinition of some inherited element), reifies the object by moving it and any stereotype applications it may have into the user model (in the appropriate containment reference, of course).

Extensions thus far are used only to define containment references for the distinct "shadow" elements representing the local view of an element inherited by some namespace. These typically are named implicitXyz (e.g., implicitPort) and are added to the Namespace::ownedMember superset as a non-standard subset, for access via the Eclipse UML2 UML API. They are in addition to queries such as Namespace::inheritedMember() and further supersets such as Namespace::member which account for inheritance by presenting the same definitions of elements in the supertype.

Extensions are not used for inheritable containment references such as MultiplicityElement::lowerValue and Connector::end. These are handled by customized setting/list implementations (InheritableSetting and InheritableEList, respectively) that take care of presenting "shadows" of inherited elements in the unset state and automatically reifying the contained elements when they are modified to effect redefinition. By implementing this inheritance in the unset state, the serialization of a model is assured never to contain an element in such a reference unless it is a redefinition. And, as these are not typically RedefinableElements according to the UML metamodel, their traceability to the elements that they redefine is implied by the reference in which they are contained (e.g., lower or upper value of a multiplicity element) and position (in case of a reference collection). Furthermore, in the case of an inheritable reference collection such as Connector::end or Operation::ownedParameter, if any element is redefined and thus requires it to be persisted (making the containment reference "set" as compared to "unset"), then all elements in the collection are persisted and are, effectively, redefinitions of the inherited elements. This is unavoidable owing to the significance of ordering in these collections.

Deviations from UML

Clearly, none of these extension and inheritance semantics can be implemented without significant deviations from the standard structure of the UML metamodel, especially as is encoded in its Ecore representation for the benefit of the EMF Run-time and applications such as EMF Compare that, to a large extent, are generic and driven by the Ecore metadata.

Although the customized UML implementation classes for UML-RT can change the outward behaviour of the API, they cannot (reasonably) change the Ecore metadata describing that API to EMF-based applications. The two most obvious deviations of the API's behaviour from what applications would expect according to the Ecore metadata are of two kinds:

  • features presenting "unsettable" semantics that in the Ecore are declared as not unsettable. This somewhat confusing nomenclature in Ecore just indicates whether a feature has a discrete "unset" state in addition to its value
  • references, especially containments, appearing to have EObject values even in the unset state (default values for EReferences are not supported by EMF)

Both of these semantic deviations are in support of inheritance: properties of an element that can be inherited from the element that it redefines (according to UML-RT incremental inheritance) must behave as though unsettable, so that the unset state can inherit the value and the set state can override it. And containment references such as MultiplicityElement::lowerValue and Connector::end must be able to present the inherited values in their unset state.

The EMF Run-time is generally well-behaved in the face of these deviations, including the ChangeRecorder that is used for automatic undo/redo of model edits. It is not concerned about receiving UNSET notifications or notifications with isSetChange from features that are not declared as unsettable; it just faithfully records set-state changes and performs eUnset() as appropriate on apply. Likewise for notifications received from extension features: they are handled correctly despite not actually being features of the notifier's EClass.

In general, applications that process notifications should behave as expected if they do not make any assumptions about the kinds of notifications that they will received based on the Ecore metadata. Applications that are primarily driven by the Ecore metadata (for more than just reacting to notifications) may have to make adjustments to account for UML-RT models if they do not just treat all features as though they were unsettable (which, in fact, is generally advisable as it does not lead to contradictions or erroneous behaviour in most cases anyways).

Façade API

The org.eclipse.papyrusrt.umlrt.uml package contains a suite of classes that provide a façade API exposing the UML-RT model structure in a friendly way, primarily targeted to extenders but also used by the Papyrus-RT UI, especially the Properties View. Instances of the façade classes correspond one-to-one with the core element of the UML representation of each UML-RT concept; this association is maintained by means of an EMF Adapter attached to the UML element.

This adapter provides the necessary coördination of the façade structure with the UML model as the latter changes with the user's edits and also maintains the UML extensions of model elements, including virtual redefinitions where necessary, amongst potentially other content.

The initial prototype of the façade API consists of these classes:

  • UMLRTModel — corresponds to a Resource in the editor's ModelSet
  • UMLRTPackage — corresponds to a Package, including the root Model, that is not a «protocolContainer» package
  • UMLRTCapsule — corresponds to a Class stereotyped as «capsule»
  • UMLRTPort — corresponds to a Port stereotyped as «rtPort»
  • UMLRTCapsulePart — properties of a capsule stereotyped as «capsulePart»
  • UMLRTConnector — a Connector in a capsule that is stereotyped as «rtConnector»
  • UMLRTProtocol — a Collaboration stereotyped as «protocol». For each protocol façade there is a corresponding conjugate that follows the naming convention and presents its messages as being of the conjugate direction kind. The conjugate protocol façade is the type of a conjugate port façade
  • UMLRTProtocolMessage — an Operation of in/out/inout direction as determined by the «rtMessageSet» Interface that defines it. The parameters of a message are exposed as the UML API because a façade would provide no significant value

The façades provide direct access to and modification of the most important properties of their UML-RT concepts. For example, names of elements, types of ports (as UMLRTProtocols), etc. The UMLRTCapsule maintains a single list of UMLRTPorts that synthesizes regular owned ports, redefining ports, virtual redefining ports (from the UML extension), and excluded ports. Other details can be obtained from the corresponding UML model element, which each façade object provides via a toUML() operation. Notification of changes is not supported; this must be done at the UML level.

The UMLRT prefix is applied to these façade class names to distinguish them clearly from the similarly named Java interfaces in the UML-RT Profile, e.g. Capsule, Protocol, CapsulePart, RTPort. Although it is not strictly necessary (the names are distinguished by their package namespace, anyways), it is convenient for readability of code to see at a glance that it is working in UML-RT terms, not UML terms, especially in sophisticated Papyrus-RT plug-ins and derived DSMLs that mix both APIs together.

Integration in Papyrus-RT

The UMLRTLanguage class in the org.eclipse.papyrusrt.umlrt.core bundle that plugs into the ILanguageService uses the UMLRTResourcesUtil to install the UML-RT implementation of the UML metamodel in place of the Eclipse UML2 UML implementation in the ModelSet-local package registry. It also bootstraps the UML-RT façade API on the model with its listeners that react to structural changes to keep the UML-RT semantics up-to-date and hooks into the TransactionalEditingDomain to ensure that undo/redo transactions do not interfere with the reification of virtual redefinition elements.

The org.eclipse.papyrusrt.umlrt.tooling.modelexplorer bundle adds a new EMF Facet customization model, Structure.custom, that enhances the Model Explorer presentation to show virtual redefinitions in the UML extension features of their namespaces. This is done by means of a generic GetExtensionFeatureQuery facet-query that takes an extension feature (an EStructuralFeature from the UML Extension metamodel) and retrieves its value from the context object, if that object is one from the UML-RT implementation that supports extension.

Capsule Structure Diagram Inheritance

For the visualization of inherited features in the Capsule Structure Diagrams, I have decided not to use the synchronization framework (org.eclipse.papyrus.infra.sync) introduced in the Papyrus Mars release. Prototyping work with this framework showed that it is simply too unwieldy, prone to failure of undo/redo, and that it is in large part obviated by work done in bug 467545 on an implementation of UML-RT semantics in the UML metamodel. So, inheritance in the diagrams is implemented by means of a coördination of GEF edit policies:

  • Canonical Edit Policy: the Papyrus-RT semantic and visual children strategies use the UML-RT façade API to find and return inherited elements
  • Inheritance Edit Policy: (NEW) manages optional tracking of the visuals of the inherited elements from the capsule structure diagram in which they are defined
  • Applied Stereotype Comment Edit Policy: specialized in Papyrus-RT to omit the comment view for inherited elements

In the Capsule Structure Diagram, all views of inherited elements reference the root definition as the semantic element, regardless of whether it is an inherited element (which is not attached to the model resource and so would break the serialization) or even a redefinition (which is a real, distinct element in the UML model). The edit-parts override the IGraphicalEditPart::resolveSemanticElement() and IAdaptable::getAdapter() APIs to resolve their notation view's reference to the appropriate redefinition or virtual "shadow" element in the local namespace for inherited elements. This ensures that UI components such as the Properties View that correctly use these APIs to get the semantic element (not simply assuming that it is the notation view's element reference) will get the correct EObject to present, so that any edits made on it will automatically trigger redefinition. However, there are many Papyrus edit-policies and other classes that do not resolve the semantic element correctly via the edit-part, which have to be overridden in Papyrus-RT to do so.

Properties View

The Papyrus-RT contributions to the Properties View are to a large extent built on the façade API, via JFace Data Bindings observable properties tailored to the façades. The org.eclipse.papyrusrt.umlrt.tooling.ui.databinding.facade has a suite of factory classes providing IFacadeProperty instances that are specialized implementations of observable data-binding properties for the façades:

  • CapsuleProperties: observable list properties for ports, capsule-parts, and connectors
  • ProtocolProperties: observable list properties for each direction-kind of protocol messages
  • NamedElementProperties: observable value property for the name

The observable lists for containment references provided by these properties support the usual Papyrus UML observable list behaviours, with an extra for inherited elements:

  • addition of new elements
  • destruction of removed elements, if exclusion does not apply
  • attempts to remove inherited or redefining elements are re-directed to exclusion, which preserves the element in the list but as an excluded element

These observables are used by a new FacadeModelElement in the properties view context to provide appropriate UI bindings for a customized multiple reference editor, the InheritableMultipleReferenceEditor. This adds buttons to the list controls for re-inheriting excluded or redefined elements and for filtering the presentation of excluded elements (by default, they are not shown). The FacadeModelElement provides full support for protocol properties via the façade API, obviating the need for the delegation pattern of observables and other details to model-elements for the message-set interfaces in the UMLRTExtModelElement. This latter class is now simplified by the removal of capsule and protocol concerns.

The properties view context/XWT contributions for capsules and protocols are updated to use the FacadeModelElement for their names, ports/parts (of capsules), and protocol messages. Likewise the creation dialog XWT descriptions for capsules and protocols that request only the name in certain UI workflows.

Model Explorer

Inherited elements in capsule (ports, parts, connectors) and protocols (messages) are presented via EMF Facets with reference queries implemented on the Façade API. By default, purely inherited elements are not shown (they are shown in the Properties View), but they can be enabled by an additional facet override in the customization dialog (the UML-RT Structure Inheritance customization). Excluded elements and redefinitions are always shown, with appropriate decorations.

The children of different dispositions are shown in a definite order:

  • Capsule
    • inherited RT ports — if shown, per above, either by redefinition/exclusion or customization to include inherited elements
    • inherited capsule-parts
    • inherited RT connectors
    • locally-defined RT ports — root definitions initially defined by the capsule
    • locally-defined capsule-parts
    • locally-defined RT connectors
    • other ports (non-RT, if applicable)
    • other attributes (that are not capsule-parts)
    • other connectors (non-RT, if applicable)
  • Protocol
    • inherited outgoing messages — if shown, per above, either by redefinition/exclusion or customization to include inherited elements. This ordering matches what was presented in the Properties View since the 0.7.x releases
    • inherited incoming messages
    • inherited in/out messages
    • locally-defined outgoing messages — root definitions initially defined by the protocol
    • locally-defined incoming messages
    • locally-defined in/out messages
    • (there is no provision in UML-RT for operations that are not protocol messages)

Back to the top