EMF framework for Event-B: Difference between revisions
imported>Colin |
imported>Colin No edit summary |
||
Line 56: | Line 56: | ||
[[Image:EMFcore3project.gif|EMF model of an Event-B Project]] | [[Image:EMFcore3project.gif|EMF model of an Event-B Project]] | ||
====References between components ==== | |||
Event-B projects contain references between elements that are contained within different components. Serialisation (persistence) is performed on a per component basis and therefore, these references must work between resources. The default mechanism for this in EMF is for the reference to be represented by a proxy, initially, after loading the component. The proxy URI is resolved when the reference is first accessed. Resolving a proxy results in the referenced component being loaded so that its contents are accessible. We wish to support this established kind of behaviour for tools that need to work at a multi-component level. | |||
However, we also wish to support tools that work on a single-component level that may involve editing the references. The user view of a reference is of a text string that contains the name identifier of the referenced element. The user may edit this identifier to a new name that may or may not exist. The edit may be made without attempting to resolve the proxy so that the validity of the reference is not tested. (When the component containing the reference is saved, the Rodin static checker will check that the reference exists and raise an error if it does not). | |||
In order to support these dual access method, we have implemented the following EMF features: | |||
* The primary feature for a relationship of this kind is an EMF reference whose type is the meta-class of the referenced element. | |||
Notes | |||
nn] = page reference to EMF book, Steinberg et al. Second Edition. | |||
This version relies on the standard EMF structural features for cross resource referencing. | |||
e.g. "refines" is of type BMachine. | |||
Methods are provided for getting and setting the referencing string without loading the referenced element. | |||
It is not even known whether the element exists. Stubs for these methods are generated from the model via EOperation | |||
meta-elements [112]. (It may be possible to define the method bodies in the model using EAnnotation [], but currently the method bodies have been added after generation). | |||
for multiplicity-one references (e.g. machine refines) 4 (generated and then hand coded) methods are provided: | |||
String getXXName(); returns the name of the referenced element either from the element or from the proxy. | |||
Void setXXName(String newName); sets the name of the referenced element (either changing its name if it has been resolved or changing | |||
the proxy reference if not). | |||
setXXXName() and unSetXXXName call the corresponding set and unset methods of the attribute they derive from. | |||
for multiplicity many references (machine sees, event refines and context extends) 1 (generated and hand coded) method is provided | |||
EList<String> getXXXName(); returns an EList of the names of the referenced elements (this is generated every time it is required from the main reference list). | |||
This is a notifying list - any changes made to it will be notified to the element that owns the original reference list. The owner will then update its reference list | |||
accordingly. [Owners of multiplicity many references have been overridden to always require notification and their eNotify method has been overridden to intercept changes to the | |||
XXX_NAME feature in order to update the main reference list accordingly] | |||
for multiplicity many references (machine sees, event refines and context extends) 3 (custom hand coded - protected) methods are also provided to assist the | |||
notification update mechanism above and to populate the getXXXName() method: | |||
String getXXName(int index); returns the name of the referenced element either from the element or from the proxy. | |||
Void setXXName(int index, String newName); REPLACES the referenced element with a proxy having the given name as fragment (either changing its name if it is a | |||
proxy or removing it and replacing it with a new proxy if resolved) | |||
Void addXXName(String newName); creates a new proxy referencing the name and adds it to the collection XX. (This method uses addUnique to avoid uniqueness checking | |||
as uniqueness checking would resolve the whole list) | |||
for owners of these references, the eResolveProxy method has been overridden to provide 'lazy' proxy generation for these references. A dummy URI (provided in | |||
CorePackage) until the proxy is resolved. The lazy proxy resolution detects that the proxy belongs to one of the references and then tries to construct it | |||
based on the owners URI (or, for event refines, on the refined machines URI). | |||
A method has been added to EventBObject to return its URI. If the element is a proxy, the proxyURI is returned. | |||
Otherwise the URI of the component's resource is returned. | |||
Note that features such as refines, that may not have any value, have the EMF attribute 'unsettable' set to true. | |||
This enables the eIsSet and eUnSet methods to be used to implement an 'unset' state. | |||
[108] | |||
Project containment of components has been changed to a cross resource containment. This involved making the containment | |||
proxy-resolving (actually, it meant making all the others non-proxy-resolving, since the unused default was 'true') | |||
and enabling cross resource containment in the generator model. | |||
[411] | |||
Extensions are also made proxy-resolving so that the possibility of extensions being separate files is allowed. (of course, | |||
they may also be within the same resource). | |||
Dual access of references either by element name or by reference relies on the element name being used as the resource name. | |||
I.e. if the name of the element is changed, it will change the resource name and break any references to it. | |||
(If the element name is changed in an editor that works at a higher level than the resource, the editor should | |||
update the references automatically) | |||
Intrinsic ID. the name attribute in NamedElement has been set to be an intrinsic ID by setting ID property to true. | |||
This means that references between elements will use name in the proxy fragments instead of an index into the collection. | |||
This makes it possible for us to retrieve and set the name of a referenced element without resolving a proxy to it. | |||
(It is also more robust reference since with the default indexing any changes to ordering in the target will break any | |||
references. The downside is that it is slower to resolve the references.) | |||
[456] | |||
the getName method in named element has been altered so that they can be used to obtain the name from the URI's | |||
fragment in proxies (where the real name attribute is null). | |||
file extensions etc. THIS IS NOT WORKING YET (currently extensions "machine" and "context" are embedded in the code). | |||
(in genmodel) the file extensions of the machine and context packages have been set to bum and buc. Actually this only affects the default | |||
EMF editor and serialisation but it helps in testing until we have our new persistence. Also the wizard for the Events package has been | |||
turned off. | |||
====Machine package==== | ====Machine package==== | ||
A ''Machine'' inherits from ''EventBComponent'' (so that it can be used in the ''components'' collection of a Project). ''Machines'', refine other machines | A ''Machine'' inherits from ''EventBComponent'' (so that it can be used in the ''components'' collection of a ''Project''). ''Machines'', refine other machines , see contexts and may contain, variables, invariants, theorems, a single variant and events. | ||
[[Image:EMFmachine1.gif|EMF model of a Machine]] | [[Image:EMFmachine1.gif|EMF model of a Machine]] |
Revision as of 15:52, 15 May 2009
This page is edited by Colin, Alexei and Fabian
Warning:
This page is being updated and is currently inconsistent and inaccurate in some areas. (The page has been updated down as far as the section on Projects). |
The Eclipse Modeling Framework
The EMF project is a modeling framework and code generation facility for building tools and other applications based on a structured data model. From a model specification described in XMI, EMF provides tools and runtime support to produce a set of Java classes for the model, along with a set of adapter classes that enable viewing and command-based editing of the model, and a basic editor.
An EMF Meta-Model of Event-B
The Event-B meta-model defines the structure of Event-B projects. The model is structured into three packages for clarity. The core package contains a structure of abstract meta-classes so that models can be treated generically as far as possible. The core package also contains mechanisms to handle extensions provided by other plug-ins and a meta-class to model entire projects. There are two sub-packages, contained with the core package, for Machine and Context. Note, that the EventB prefix is used to indicate that a meta-class is abstract (i.e. cannot be instantiated except via one of its subclasses).
Abstract Basis
The root of all meta-classes in the Event-B EMF model is the abstract base class, EventBObject this provides some convenience methods to access containing or contained elements of a specified type and a method to obtain the URL of an element's package. EventBObject extends the EMF class, EModelElement, which provides a facility to store EAnnotations in any EventBObject. (EAnnotations give a flexible and efficient way to store information that is not part of the main model. For example this is used to store some information contained in the Rodin database, which must be preserved but is not of interest in the EMF modelling tools).
EventBElement provides a common abstract base class for all EventBObjects that are elements of the model. This meta-class provides extensibility features that are described later.
EventBCommentedElement provides the ability to comment elements. It inherits a string attribute, comment from EventBCommented. (The use of a separate meta-class, outside the main inheritance hierarchy gives more flexibility for future modifications if other elements need to be commented. Hence if client code refers to comments via EventBCommented rather than EventBCommentedElement they will not be affected if, in the future, other elements inherit EventBCommented).
Similarly, EventBNamedCommentedElement adds the ability to name elements by inheriting a string attribute, name from EventBNamed. (Currently, a named but not commented element is not provided).
EventBExpression provides a string attribute, expression, for an Event-B mathematical expression. Note that this class extends EventBCommentedElement since our current need (Variant) is for expression elements not to be commented but not named.
EventBPredicate, provides a string attribute, predicate for an Event-B mathematical predicate. Note that this class extends EventBNamedCommentedElement since our current need is for all predicate elements to be commented and named.
EventBDerivedPredicate, extends EventBPredicate and provides a boolean attribute, theorem to indicate that the predicate is a theorem that should be derived (from previous predicates in the same container).
Extensibility Mechanism
The Extensibility mechanism caters for extensions (i.e. new elements and/or attributes) that have been defined in the Rodin database. The extension mechanism can also be used to store temporary volatile modelling data that will not be persisted. The extensions will only be persisted if valid Rodin identifiers are provided. The extension data is contained by the abstract meta-class EventBElement and hence can be attached to any Event-B model element. Two mechanisms are provided, one for simple attributes (corresponding to Rodin attribute extensions) and one for extension elements (corresponding to Rodin element extensions).
Attribute extensions are contained in a collection attributes. They utilise an intermediate StringToAttributeMapEntry class which triggers the EMF generator to provide the collection as a special kind of list that can be accessed also as a map. The map key, contained in the StringToAttributeMapEntry class should correspond to a valid Rodin extension id if persistence is required. The target meta-class, Attribute contains the type, which is an enumeration corresponding to the Rodin attribute types, and the value, which is a java object allowing for different attribute types. This feature is used in the following way:
- if, at load time, a Rodin attribute is found that is not recognised as a known attribute of the current element type, the attribute will be stored in the generic attributes collection using its type identification as the key. Such unknown attributes will be restored at save time.
- all elements of an unknown extension element are treated in this way.
- if at save time, any extensions are found that do not have a valid Rodin extension identifier as their attribute map key, these will be assumed to be volatile and will be discarded.
Element extensions are represented by a collection, extensions, of a meta-class, Extensions, which has an extensionId. This mechanism can be used in several ways.
- if a synchroniser (see persistence section) has been registered for the Rodin element type; at load time, this is used to create an EMF model element, which should extend Extension, and the element is added to the extensions container of the parent. (Usually this will be a root element for a model). At save time, the same synchroniser will be used to persist the element.
- if a synchroniser has not been registered; at load time, unknown Rodin elements will be instantiated as generic Extension elements and their attributes will be contained in this element's attributes collection. (Note that the Extension element could contain further recognised or unrecognised elements, which would be added to it's extensions collection). At save time, these elements would be converted back to their corresponding Rodin elements using the extensionId and attribute map key, which are also the Rodin extension identifiers.
- if at save time, any extensions are found that do not have a valid Rodin extension identifier as their extensionId, these will be assumed to be volatile and will be discarded.
Project
Event-B projects are modelled in the Event-B EMF model. This supports tools that can display and/or manipulate the project contents. A Project contains a collection of components. Project extends EventBNamedCommentedElement. This allows it to contain Extensions and Attributes as well as providing it with a name and comment. Since persistence works at the component level, the project containments are 'across-resource'. Hence EMF's support for proxy resolution in containments is utilised for the project level model. (By default, proxy resolution is only provided for reference relationships).
References between components
Event-B projects contain references between elements that are contained within different components. Serialisation (persistence) is performed on a per component basis and therefore, these references must work between resources. The default mechanism for this in EMF is for the reference to be represented by a proxy, initially, after loading the component. The proxy URI is resolved when the reference is first accessed. Resolving a proxy results in the referenced component being loaded so that its contents are accessible. We wish to support this established kind of behaviour for tools that need to work at a multi-component level.
However, we also wish to support tools that work on a single-component level that may involve editing the references. The user view of a reference is of a text string that contains the name identifier of the referenced element. The user may edit this identifier to a new name that may or may not exist. The edit may be made without attempting to resolve the proxy so that the validity of the reference is not tested. (When the component containing the reference is saved, the Rodin static checker will check that the reference exists and raise an error if it does not).
In order to support these dual access method, we have implemented the following EMF features:
- The primary feature for a relationship of this kind is an EMF reference whose type is the meta-class of the referenced element.
Notes
nn] = page reference to EMF book, Steinberg et al. Second Edition.
This version relies on the standard EMF structural features for cross resource referencing. e.g. "refines" is of type BMachine.
Methods are provided for getting and setting the referencing string without loading the referenced element. It is not even known whether the element exists. Stubs for these methods are generated from the model via EOperation meta-elements [112]. (It may be possible to define the method bodies in the model using EAnnotation [], but currently the method bodies have been added after generation).
for multiplicity-one references (e.g. machine refines) 4 (generated and then hand coded) methods are provided: String getXXName(); returns the name of the referenced element either from the element or from the proxy. Void setXXName(String newName); sets the name of the referenced element (either changing its name if it has been resolved or changing the proxy reference if not). setXXXName() and unSetXXXName call the corresponding set and unset methods of the attribute they derive from.
for multiplicity many references (machine sees, event refines and context extends) 1 (generated and hand coded) method is provided EList<String> getXXXName(); returns an EList of the names of the referenced elements (this is generated every time it is required from the main reference list). This is a notifying list - any changes made to it will be notified to the element that owns the original reference list. The owner will then update its reference list accordingly. [Owners of multiplicity many references have been overridden to always require notification and their eNotify method has been overridden to intercept changes to the XXX_NAME feature in order to update the main reference list accordingly]
for multiplicity many references (machine sees, event refines and context extends) 3 (custom hand coded - protected) methods are also provided to assist the notification update mechanism above and to populate the getXXXName() method: String getXXName(int index); returns the name of the referenced element either from the element or from the proxy. Void setXXName(int index, String newName); REPLACES the referenced element with a proxy having the given name as fragment (either changing its name if it is a
proxy or removing it and replacing it with a new proxy if resolved)
Void addXXName(String newName); creates a new proxy referencing the name and adds it to the collection XX. (This method uses addUnique to avoid uniqueness checking as uniqueness checking would resolve the whole list)
for owners of these references, the eResolveProxy method has been overridden to provide 'lazy' proxy generation for these references. A dummy URI (provided in CorePackage) until the proxy is resolved. The lazy proxy resolution detects that the proxy belongs to one of the references and then tries to construct it based on the owners URI (or, for event refines, on the refined machines URI).
A method has been added to EventBObject to return its URI. If the element is a proxy, the proxyURI is returned. Otherwise the URI of the component's resource is returned.
Note that features such as refines, that may not have any value, have the EMF attribute 'unsettable' set to true.
This enables the eIsSet and eUnSet methods to be used to implement an 'unset' state.
[108]
Project containment of components has been changed to a cross resource containment. This involved making the containment proxy-resolving (actually, it meant making all the others non-proxy-resolving, since the unused default was 'true') and enabling cross resource containment in the generator model. [411]
Extensions are also made proxy-resolving so that the possibility of extensions being separate files is allowed. (of course, they may also be within the same resource).
Dual access of references either by element name or by reference relies on the element name being used as the resource name. I.e. if the name of the element is changed, it will change the resource name and break any references to it. (If the element name is changed in an editor that works at a higher level than the resource, the editor should
update the references automatically)
Intrinsic ID. the name attribute in NamedElement has been set to be an intrinsic ID by setting ID property to true. This means that references between elements will use name in the proxy fragments instead of an index into the collection. This makes it possible for us to retrieve and set the name of a referenced element without resolving a proxy to it. (It is also more robust reference since with the default indexing any changes to ordering in the target will break any
references. The downside is that it is slower to resolve the references.) [456] the getName method in named element has been altered so that they can be used to obtain the name from the URI's fragment in proxies (where the real name attribute is null).
file extensions etc. THIS IS NOT WORKING YET (currently extensions "machine" and "context" are embedded in the code). (in genmodel) the file extensions of the machine and context packages have been set to bum and buc. Actually this only affects the default EMF editor and serialisation but it helps in testing until we have our new persistence. Also the wizard for the Events package has been turned off.
Machine package
A Machine inherits from EventBComponent (so that it can be used in the components collection of a Project). Machines, refine other machines , see contexts and may contain, variables, invariants, theorems, a single variant and events.
Events
Events contain parameters, witnesses, refines relationships with other events, guards and actions. Witnesses, link with other parameters (via a subtype of BReferenceElement which may be resolved). Similarly, event refinement relationships link to other events (via a subtype of BReferenceElement which may be resolved). The enumerated type, BConvergence, provides the values for the convergence property of an event.
Context package
A Context inherits from component. Contexts, extend other contexts (via a subtype of BReferenceElement which may be resolved), and contain sets, constants, axioms and theorems. (Note that the BTheorem meta-class is the same one that appeared in the Machine package).
Event-B Mathematical Language Extension
Using the Extension mechanism an EMF extension for the Mathmetical Language of EventB will be created. This means expressions, predicates and substitutions will be available as EMF models too.
As the RodinDB only saves these constructs as plain strings, their EMF representation will be recreated every time a model is loaded. The existing RodinParser in combination with a conversion component will be used for this task. To avoid unnecessary parsing the creation of these models will be postponed until the models are needed. For example, it will be up to the tool developers to decide when they need a fully resolved structure of predicates. API methods in the Text Tools will ease parsing and model construction for tool developers.
Persistence
The Persistence package will override the default EMF persistence so that models created with the Event-B EMF framework will be serialised into the Rodin Database. The serialisation will make use of the Rodin API so that it is decoupled from the serialisation of the Rodin database. Serialisation will synchronise changes with the Rodin Database so that only elements that have been altered are updated. The Persistence API will provide methods to open/create Rodin projects, load and unload components (from Rodin Database to cache), save changes, register listeners to projects and components and resolve references between elements.
Text Tools
As several tools based on the EventB meta-model will deal with a textual representation of it, a component called 'Text Tools' will be created. Text Tools will offer an API for basic tasks such as:
- Define a concrete syntax for the structure of machines and contexts
- Conversion from an EventB meta-model to text, i.e., pretty-print with configurable layout
- Parsing of text input which produces an EventB meta-model
Structural parsing
The Rodin core already provides a parser for expressions, predicates and substitutions. Therefore Text Tools will only provide a parser for the structural parts of the text representation of EventB machines and contexts. This parser will treat expressions, predicates and substitutions as plain strings that are stored in attributes in the meta-model. As described in section Event-B Mathematical Language Extension the full mathematical language will be supported as an extension to the EventB meta-model. Tools that are interested in working on a fully parsed version of an expression, predicate or substitution will be able to use helper methods of the Text Tools API. These helper methods will make use of the existing Rodin parser and convert the resulting AST to the meta-model.
Fallback strategy
When the user is editing the textual representation of a machine or context the input may contain syntactic errors which prevent converting the parse result into an EMF model. As the user might wish to save the text representation in this syntactically incorrect state, Text Tools will provide a fallback strategy for this case. API methods will be provided to store the plain text into the RodinDB. This plain text will be used as a basis for editing next time the model is loaded via Text Tools.
Conflict resolution
When Text Tools loads an EventB meta-model from the Rodin Database it will detect any conflicts in the model. Conflicts will occur if other editors, that do not work via Text Tools, have changed the model in the RodinDB after Text Tools has stored a syntactically incorrect version as plain text. In this case the tool that is using Text Tools to load the model will be informed about the conflict and asked to resolve it. Strategies to solve these conflicts could be 'automatic overwriting based on time stamps' or using the editors described in the section Compare/Merge Editor.
Tools That Will Use the Framework
The framework described above is not yet available. However, we already plan to use it in some tools.
Compare/Merge Editor
In several situations conflicts between different versions of an Event-B model can occur. Often the responsible tool will not be able to resolve these conflicts automatically and user interaction is required. A compare and merge editor for Event-B models will help users to solve these conflicts. This editor will be based on the EMF Compare sub-project. It will compare the two conflicting versions and present the differences to the user. This visualization of the model will resemble the Structure Editor.
If one of the two versions of the machine/context contains an invalid structure that means it is only available as text, the EMF based Compare/Merge editor cannot be used. A textual Compare/Merge editor will be available as an alternative view (integrated with the EMF Compare/Merge editor). The second view will be based on the Text Editor.
Usage scenarios are, for example:
- Merging after a conflict between RodinDB and Text Editor (as described in Text Tools)
- Team-based development, for example, using SVN or CVS
- Comparison of an abstract and a refining machine, highlighting the differences
Text Editor
Requests by several users have shown that there is demand for a text editor for EventB models. Based on the EventB meta-model and the Text Editor Framework, a state-of-the-art text editor will be created. The editor will make use of Text Tools and will provide an extensible set of features, such as (syntactical and semantical) highlighting, code completion, quick navigation and outline view.
The text editor will be available in two forms. A first class Eclipse editor will offer editing of full machines and contexts. In addition a pop-up editor will be created that can be used by other tools to allow their users text editing of sub-components in machines and contexts. An example is the Structure Editor, which will offer a pop-up text editor allowing the user to edit a single expression or a compound sub-component such as an event.
Structure Editor
EMF provides support to generate structured (e.g. tree, list, table based) editors for models. An adapted version of these editors will allow users to edit machine and context elements within a structure using menu-guided selections. To allow feature-rich editing of elements containing expressions, predicates and substitutions this editor will use the pop-up variant of the Text Editor.
Project Diagram Editor
A diagrammatic editor will be produced that shows the structure of an Event-B Project in terms of it's Machines and Contexts with their refines, sees and extends relationships. (This will replace the current UML-B package diagram). The Project Diagram editor will be produced using the Graphical Modelling Framework (GMF). It will allow machines and contexts to be created/deleted and their relationships changed. A feature to create a 'starting point' refinement of a machine, will be included.
UML-B
UML-B will be re-implemented as an extension to the Event-B meta-model. The UML-B meta-classes will extend and add to the meta-classes of Event-B. This will provide greater integration between the EMF based Event-B editors and the UML-B diagrammatic editors.
Refinement Pattern Editor
The EMF framework will be used to implement the text editor for the Event-B pattern plugin. The syntax of facets - Event-B model templates used to describe patterns - is an extension of the Event-B syntax.
An editor for composing two machines based on shared events has been developed by Southampton. This tool will be re-implemented to utilise the Event-B EMF framework.
See Parallel Composition using Event-B.
Feature Composition Tool
An editor for composing two machines based on feature selection has been developed by Southampton. The tool (which is already based on EMF) will be re-implemented to utilise the Event-B EMF framework. See Feature Composition Plug-in.
Internal Documentation
The following pages contain documentation that we use internally only (not to be included in deliverable):