blob: 51f8ba6b301f6c22574cbd0a40b92e79a88307b8 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Xtext - Integration with EMF</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description"
content="The website of Eclipse Xtext, an open-source framework for development of programming languages and domain-specific languages">
<meta name="author" content="Sven Efftinge">
<meta name="author" content="Miro Spoenemann">
<!-- styles -->
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Le fav and touch icons -->
<link rel="shortcut icon" href="/Xtext/images/favicon.png">
<link href="/Xtext/css/bootstrap.css" rel="stylesheet" type='text/css'>
<link href="/Xtext/css/bootstrap-responsive.css" rel="stylesheet" type='text/css'>
<link href="/Xtext/css/shield-responsive.css" rel="stylesheet" type='text/css'>
<link href='/Xtext/css/fonts.css' rel='stylesheet' type='text/css'>
<link href="/Xtext/css/prettyPhoto.css" rel="stylesheet" media="screen" type='text/css'>
<link href="/Xtext/css/prettify.css" type="text/css" rel="stylesheet"/>
<link href="/Xtext/css/style.css" rel="stylesheet" type='text/css'>
<!-- cover flow -->
<link href="/Xtext/css/coverflow.css" rel="stylesheet" type='text/css'>
<!--[if lt IE 9]>
<link href="/css/iebugs.css" rel="stylesheet" type='text/css'>
<![endif]-->
<!-- BEGIN Cookie Consent
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script>
<script>
window.addEventListener("load", function(){
window.cookieconsent.initialise({
"palette": {
"popup": {
"background": "#000"
},
"button": {
"background": "#f1d600"
}
},
"theme": "edgeless",
"type": "opt-in",
onInitialise: function (status) {
var type = this.options.type;
var didConsent = this.hasConsented();
if (type == 'opt-in' && didConsent) {
// TODO: enable cookies
}
if (type == 'opt-out' && !didConsent) {
// TODO: disable cookies
}
},
onStatusChange: function(status, chosenBefore) {
var type = this.options.type;
var didConsent = this.hasConsented();
if (type == 'opt-in' && didConsent) {
// TODO: enable cookies
}
if (type == 'opt-out' && !didConsent) {
// TODO: disable cookies
}
},
onRevokeChoice: function() {
var type = this.options.type;
if (type == 'opt-in') {
// TODO: disable cookies
}
if (type == 'opt-out') {
// TODO: enable cookies
}
},
"content": {
"href": "http://www.eclipse.org/legal/privacy.php"
}
})});
</script>
END Cookie Consent -->
</head>
<body>
<header class="site-header">
<!-- Navbar -->
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse"
data-target=".nav-collapse"> <span class="icon-bar"></span> <span
class="icon-bar"></span> <span class="icon-bar"></span>
</a> <a class="brand" href="/Xtext/index.html"></a>
<div class="nav-collapse collapse" style="height: 0px;">
<ul class="nav">
<!--li ><a href="/Xtext/news.html">News</a></li-->
<li ><a href="/Xtext/download.html">Download</a></li>
<li ><a href="/Xtext/documentation/index.html">Documentation</a></li>
<li ><a href="/Xtext/community.html">Community</a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Support &amp; Trainings<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="https://www.itemis.com/en/xtext/support-and-team/" target="_blank">itemis</a></li>
<li><a href="https://typefox.io/trainings-2" target="_blank">TypeFox</a></li>
</ul>
</li>
<li ><a href="http://xtend-lang.org">Xtend</a></li>
</ul>
<!--div class="nav pull-right">
<li ><a><iframe src="https://ghbtns.com/github-btn.html?user=eclipse&repo=xtext&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe></a></li>
</div-->
</div>
<!--/.nav-collapse -->
</div>
</div>
</div>
<!-- Navbar End -->
</header>
<div class="page-content">
<script>
function startSearch(event) {
if (event.keyCode == 13) {
var q = 'site:eclipse.org/Xtext/documentation+' + event.target.value;
window.open('https://www.google.com/search?q=' + q, "_self");
}
}
</script>
<div class="wrapper">
<div id="page">
<div class="inner">
<div id="maincontainer" class="container">
<span class="edit-on-github pull-right">
<a href="https://github.com/eclipse/xtext/edit/website-published/xtext-website/documentation/308_emf_integration.md">Edit on Github</a>
</span>
<div class="span3" style="margin-left: 0px;">
<div class="search-bar">
<img src="/Xtext/images/search-gray.png"/>
<input type="search" id="google-search" onkeyup="startSearch(event);"/>
</div>
<ul id="nav-outline" style="margin-left: 0px;">
<li class="nav-part">Getting Started</li>
<li><a href="102_domainmodelwalkthrough.html">15 Minutes Tutorial</a></li>
<li><a href="103_domainmodelnextsteps.html">15 Minutes Tutorial - Extended</a></li>
<li><a href="104_jvmdomainmodel.html">Five simple steps to your JVM language</a></li>
<li class="nav-part">Reference Documentation</li>
<li><a href="301_grammarlanguage.html">The Grammar Language</a></li>
<li><a href="302_configuration.html">Configuration</a></li>
<li><a href="303_runtime_concepts.html">Language Implementation</a></li>
<li><a href="305_xbase.html">Integration with Java</a></li>
<li><a href="307_special_languages.html">Typical Language Configurations</a></li>
<li><a href="308_emf_integration.html">Integration with EMF</a></li>
<li><a href="310_eclipse_support.html">Eclipse Support</a></li>
<li><a href="330_web_support.html">Web Editor Support</a></li>
<li><a href="340_lsp_support.html">LSP Support</a></li>
<li><a href="350_continuous_integration.html">Continuous Integration</a></li>
</ul>
</div>
<div class="span8 doc-contents">
<h1 id="emf-integration">Integration with EMF</h1>
<p>Xtext relies heavily on EMF internally, but it can also be used as the serialization back-end of other EMF-based tools. In this section we introduce the basic concepts of the <a href="http://www.eclipse.org/modeling/emf/">Eclipse Modeling Framework (EMF)</a> in the context of Xtext. If you want to learn more about EMF, we recommend reading the <a href="http://www.eclipse.org/modeling/emf/">EMF book</a>.</p>
<h2 id="model-metamodel">Model, Ecore Model, and Ecore</h2>
<p>Xtext uses EMF models as the in-memory representation of any parsed text files. This in-memory object graph is called the <em>abstract syntax tree</em> (AST). Depending on the community this concepts is also called <em>document object model (DOM)</em>, <em>semantic model</em>, or simply <em>model</em>. We use <em>model</em> and <em>AST</em> interchangeably. Given the example model from the <a href="102_domainmodelwalkthrough.html">domainmodel tutorial</a>, the AST looks similar to this</p>
<p><img src="images/ast.png" alt="Sample AST" /></p>
<p>The <em>AST</em> should contain the essence of your textual models. It abstracts over syntactical information. It is used by later processing steps, such as validation, compilation or interpretation. In EMF a model is made up of instances of <em>EObjects</em> which are connected. An <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObject</a> is an instance of an <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EClass.java">EClass</a>. A set of <em>EClasses</em> can be contained in a so called <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EPackage.java">EPackage</a>, which are both concepts of <em>Ecore</em>. In Xtext, meta-models are either inferred from the grammar or predefined by the user (see the section on <a href="301_grammarlanguage.html#package-declarations">EPackage declarations</a> for details). The next diagram shows the meta-model of our example:</p>
<p><img src="images/metamodel.png" alt="Sample meta model" /></p>
<p>The language in which the meta-model is defined is called <em>Ecore</em>. In other words, the meta-model is the Ecore model of your language. Ecore is an essential part of EMF. Your models instantiate the meta-model, and your meta-model instantiates Ecore. To put an end to this recursion, Ecore is defined in itself (an instance of itself).</p>
<p>The meta-model defines the types of the semantic nodes as Ecore <em>EClasses</em>. EClasses are shown as boxes in the meta-model diagram, so in our example, <em>Model</em>, <em>Type</em>, <em>SimpleType</em>, <em>Entity</em>, and <em>Property</em> are EClasses. An EClass can inherit from other EClasses. Multiple inheritance is allowed in Ecore, but of course cycles are forbidden.</p>
<p>EClasses can have <em>EAttributes</em> for their simple properties. These are shown inside the EClasses nodes. The example contains two EAttributes <em>name</em> and one EAttribute <em>multi</em>. The domain of values for an EAttribute is defined by its <em>EDataType</em>. Ecore ships with some predefined <em>EDataTypes</em>, which essentially refer to Java primitive types and other immutable classes like <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/String.html">String</a>. To make a distinction from the Java types, the <em>EDataTypes</em> are prefixed with an <em>E</em>. In our example, that is <em>EString</em> and <em>EBoolean</em>.</p>
<p>In contrast to EAttributes, <em>EReferences</em> point to other EClasses. The <em>containment</em> flag indicates whether an EReference is a <em>containment reference</em> or a <em>cross-reference</em>. In the diagram, references are edges and containment references are marked with a diamond. At the model level, each element can have at most one container, i.e. another element referring to it with a containment reference. This infers a tree structure to the models, as can be seen in the sample model diagram. On the other hand, <em>cross-references</em> refer to elements that can be contained anywhere else. In the example, <em>elements</em> and <em>properties</em> are containment references, while <em>type</em> and <em>extends</em> are cross-references. For reasons of readability, we skipped the cross-references in the sample model diagram. Note that in contrast to other parser generators, Xtext creates ASTs with linked cross-references.</p>
<p>Other than associations in UML, EReferences in Ecore are always owned by one EClass and only navigable in the direction form the owner to the type. Bi-directional associations must be modeled as two references, being <em>eOpposite</em> of each other and owned by one end of the associations.</p>
<p>The superclass of EAttributes and EReferences is <em>EStructuralFeature</em> and allows to define a name and a cardinality by setting <em>lowerBound</em> and <em>upperBound</em>. Setting the latter to -1 means ‘unbounded’.</p>
<p>The common super type of EDataType and EClass is <em>EClassifier</em>. An <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EPackage.java">EPackage</a> acts as a namespace and container of EClassifiers.</p>
<p>We have summarized these most relevant concepts of Ecore in the following diagram:</p>
<p><img src="images/ecore.png" alt="Ecore concepts" /></p>
<h2 id="emf-codegen">EMF Code Generation</h2>
<p>EMF also ships with a code generator that generates Java classes from your Ecore model. The code generators input is the so called <em>EMF generator model</em>. It decorates (references) the Ecore model and adds additional information for the Ecore → Java transformation. Xtext will automatically generate a generator model with reasonable defaults for all generated meta-models, and run the EMF code generator on them.</p>
<p>The generated classes are based on the EMF runtime library, which offers a lot of infrastructure and tools to work with your models, such as persistence, reflection, referential integrity, lazy loading etc.</p>
<p>Among other things, the code generator will generate</p>
<ul>
<li>A Java interface and a Java class for each EClassifier in your Ecore model. By default, all classes will implement the interface <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObject</a>, linking a lot of runtime functionality.</li>
<li>A Java bean property for each EStructuralFeature (member variable, accessor methods).</li>
<li>A package interface and class, holding singleton objects for all elements of your Ecore model, allowing reflection. EPackages are also registered to the <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EPackage.java">Registry</a> to be usable at runtime.</li>
<li>A factory interface and class for creating instances.</li>
<li>An abstract switch class implementing a visitor pattern to avoid if-instanceof-cascades in your code.</li>
</ul>
<h2 id="xtext-resource">XtextResource Implementation</h2>
<p>Xtext provides an implementation of EMF’s resource, the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a>. This does not only encapsulate the parser that converts text to an EMF model but also the <a href="303_runtime_concepts.html#serialization">serializer</a> working the opposite direction. That way, an Xtext model just looks like any other Ecore-based model from the outside, making it amenable for the use by other EMF based tools. So in the ideal case, you can switch the serialization format of your models to your self-defined DSL by just replacing the resource implementation used by your other modeling tools.</p>
<p><img src="images/emf-integration.png" alt="" /></p>
<p>The generator fragment <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext.xtext.generator/src/org/eclipse/xtext/xtext/generator/resourceFactory/ResourceFactoryFragment2.xtend">ResourceFactoryFragment2</a> registers a factory for the <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a> to EMF’s resource factory registry, such that all tools using the default mechanism to resolve a resource implementation will automatically get that resource implementation.</p>
<p>Using a self-defined textual syntax as the primary storage format has a number of advantages over the default XMI serialization, e.g.</p>
<ul>
<li>You can use well-known and easy-to-use tools and techniques for manipulation, such as text editors, regular expressions, or stream editors.</li>
<li>You can use the same tools for version control as you use for source code. Comparing and merging is performed in a syntax the developer is familiar with.</li>
<li>It is impossible to break the model such that it cannot be reopened in the editor again.</li>
<li>Models can be fixed using the same tools, even if they have become incompatible with a new version of the Ecore model.</li>
</ul>
<p>Xtext targets easy to use and naturally feeling languages. It focuses on the lexical aspects of a language a bit more than on the semantic ones. As a consequence, a referenced Ecore model can contain more concepts than are actually covered by the Xtext grammar. As a result, not everything that is possibly expressed in the EMF model can be serialized back into a textual representation with regards to the grammar. So if you want to use Xtext to serialize your models as described above, it is good to have a couple of things in mind:</p>
<ul>
<li>Prefer optional rule calls (cardinality <em>?</em> or <em>*</em>) to mandatory ones (cardinality <em>+</em> or default), such that missing references will not obstruct serialization.</li>
<li>You should not use an Xtext-Editor on the same model instance as a self-synchronizing other editor, e.g. a canonical GMF editor (see the <a href="308_emf_integration.html#gmf-integration-stage1">EMF integration chapter</a> for details). The Xtext parser replaces re-parsed subtrees of the AST rather than modifying it, so elements will become stale. As the Xtext editor continuously re-parses the model on changes, this will happen rather often. It is safer to synchronize editors more loosely, e.g. on file changes.</li>
<li>Implement an <a href="#fragment-provider">IFragmentProvider</a> to make the XtextResource return stable fragments for its contained elements, e.g. based on composite names rather than order of appearance.</li>
<li>Implement an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/naming/IQualifiedNameProvider.java">IQualifiedNameProvider</a> and an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/scoping/IScopeProvider.java">IScopeProvider</a> (<a href="303_runtime_concepts.html#scoping">how-to</a>) to make the names of all linkable elements in cross-references unique.</li>
<li>Provide an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/formatting/IFormatter.java">IFormatter</a> (<a href="303_runtime_concepts.html#formatting">how-to</a>) to improve the readability of the generated textual models.</li>
<li>Register an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/parser/antlr/IReferableElementsUnloader.java">IReferableElementsUnloader</a> to turn deleted/replaced model elements into EMF proxies. Design the rest of your application such that it does never keep references to <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObjects</a> or to cope with proxies. That will improve the stability of your application drastically.</li>
<li>Xtext will register an EMF <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/resource/Resource.java">Factory</a>, so resources with the file extension you entered when generating the Xtext plug-ins will be automatically loaded in an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a> when you use EMF’s <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/resource/ResourceSet.java">ResourceSet</a> API to load it.</li>
</ul>
<h2 id="fragment-provider">Referencing From EMF</h2>
<p>In some cases you may want to be able to reference an <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObject</a> of an Xtext model from another EMF artifact that is not managed by Xtext. In those cases URIs are used, which are made up of a part identifying the resource and a second part that points to an object. Each <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObject</a> contained in a resource can be identified by a so called <em>fragment</em>.</p>
<p>A fragment is a part of an EMF URI and needs to be unique per resource.</p>
<p>The generic resource shipped with EMF provides a generic path-like computation of fragments. These fragment paths are unique by default and do not have to be serialized. On the other hand, they can be easily broken by reordering the elements in a resource.</p>
<p>With an XMI or other binary-like serialization it is also common and possible to use UUIDs. UUIDs are usually binary and technical, so you don’t want to deal with them in human readable representations.</p>
<p>However with a textual concrete syntax we want to be able to compute fragments out of the human readable information. We don’t want to force people to use UUIDs (i.e. synthetic identifiers) or fragile, relative, generic paths in order to refer to <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObjects</a>.</p>
<p>Therefore one can contribute an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/IFragmentProvider.java">IFragmentProvider</a> per language. It has two methods: <code>getFragment(EObject, Fallback)</code> to calculate the fragment of an <a href="https://github.com/eclipse/emf/blob/R2_9_0/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/EObject.java">EObject</a> and <code>getEObject(Resource, String, Fallback)</code> to go the opposite direction. The <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/IFragmentProvider.java">Fallback</a> interface allows to delegate to the default strategy - which usually uses the fragment paths described above.</p>
<p>The following snippet shows how to use qualified names as fragments:</p>
<pre><code class="language-java">public QualifiedNameFragmentProvider implements IFragmentProvider {
@Inject
private IQualifiedNameProvider qualifiedNameProvider;
public String getFragment(EObject obj, Fallback fallback) {
String qName = qualifiedNameProvider.getQualifiedName(obj);
return qName != null ? qName : fallback.getFragment(obj);
}
public EObject getEObject(Resource resource,
String fragment,
Fallback fallback) {
if (fragment != null) {
Iterator&lt;EObject&gt; i = EcoreUtil.getAllContents(resource, false);
while(i.hasNext()) {
EObject eObject = i.next();
String candidateFragment = (eObject.eIsProxy())
? ((InternalEObject) eObject).eProxyURI().fragment()
: getFragment(eObject, fallback);
if (fragment.equals(candidateFragment))
return eObject;
}
}
return fallback.getEObject(fragment);
}
}
</code></pre>
<p>For performance reasons it is usually a good idea to navigate the resource based on the fragment information instead of traversing it completely. If you know that your fragment is computed from qualified names and your model contains something like <em>NamedElements</em>, you should split your fragment into those parts and query the root elements, the children of the best match and so on.</p>
<p>Furthermore it’s a good idea to have some kind of conflict resolution strategy to be able to distinguish between equally named elements that actually are different, e.g. properties may have the very same qualified name as entities.</p>
<h2 id="gmf-integration">Integration with GMF Editors</h2>
<p>We do no longer maintain the GMF example code and have removed it from our installation. You can still access the last version of the source code form our <a href="https://github.com/eclipse/xtext/tree/v2.10.0/examples/org.eclipse.xtext.xtext.ui.examples/contents">source code repository</a>.</p>
<p>The <a href="http://www.eclipse.org/modeling/gmp/?project=gmf">Graphical Modeling Framework (GMF)</a> allows to create graphical diagram editors for Ecore models. To illustrate how to build a GMF editor on top of an <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a> we have provided an example. You must have the Helios version 2.3 of GMF Notation, Runtime and Tooling and their dependencies installed in your workbench to run the example. With other versions of GMF it might work to regenerate the diagram code.</p>
<p>The example consists of a number of plug-ins</p>
<table>
<thead>
<tr>
<th style="text-align: left">Plug-in</th>
<th style="text-align: left">Framework</th>
<th style="text-align: left">Purpose</th>
<th style="text-align: left">Contents</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">o.e.x.example.gmf</td>
<td style="text-align: left">Xtext</td>
<td style="text-align: left">Xtext runtime plug-in</td>
<td style="text-align: left">Grammar, derived metamodel and language infrastructure</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.e.g.ui</td>
<td style="text-align: left">Xtext</td>
<td style="text-align: left">Xtext UI plug-in</td>
<td style="text-align: left">Xtext editor and services</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.e.g.edit</td>
<td style="text-align: left">EMF</td>
<td style="text-align: left">EMF.edit plug-in</td>
<td style="text-align: left">UI services generated from the metamodel</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.e.g.models</td>
<td style="text-align: left">GMF</td>
<td style="text-align: left">GMF design models</td>
<td style="text-align: left">Input for the GMF code generator</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.e.g.diagram</td>
<td style="text-align: left">GMF</td>
<td style="text-align: left">GMF diagram editor</td>
<td style="text-align: left">Purely generated from the GMF design models</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.e.g.d.extensions</td>
<td style="text-align: left">GMF and Xtext</td>
<td style="text-align: left">GMF diagram editor extensions</td>
<td style="text-align: left">Manual extensions to the generated GMF editor for integration with Xtext</td>
</tr>
<tr>
<td style="text-align: left">o.e.x.gmf.glue</td>
<td style="text-align: left">Xtext and GMF</td>
<td style="text-align: left">Glue code</td>
<td style="text-align: left">Generic code to integrate Xtext and GMF</td>
</tr>
</tbody>
</table>
<p>We will elaborate the example in three stages.</p>
<h3 id="gmf-integration-stage1">Stage 1: Make GMF Read and Write the Semantic Model As Text</h3>
<p>A diagram editor in GMF by default manages two resources: One for the semantic model, that is the model we’re actually interested in for further processing. In our example it is a model representing entities and data types. The second resource holds the notation model. It represents the shapes you see in the diagram and their graphical properties. Notation elements reference their semantic counterparts. An entity’s name would be in the semantic model, while the font to draw it in the diagram would be stored the notation model. Note that in the integration example we’re only trying to represent the semantic resource as text.</p>
<p>To keep the semantic model and the diagram model in sync, GMF uses a so called <em>CanonicalEditPolicy</em>. This component registers as a listener to the semantic model and automatically updates diagram elements when their semantic counterparts change, are added or are removed. Some notational information can be derived from the semantic model by some default mapping, but usually there is a lot of graphical stuff that the user wants to change to make the diagram look better.</p>
<p>In an Xtext editor, changes in the text are transferred to the underlying <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a> by a call to the method <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource.update(int, int, String)</a>, which will trigger a partial parsing of the dirty text region and a replacement of the corresponding subtree in the AST model (semantic model).</p>
<p>Having an Xtext editor and a canonical GMF editor on the same resource can therefore lead to loss of notational information, as a change in the Xtext editor will remove a subtree in the AST, causing the <em>CanonicalEditPolicy</em> to remove all notational elements, even though it was customized by the user. Xtext rebuilds the AST and the notation model is restored using the default mapping. It is therefore not recommended to let an Xtext editor and a canonical GMF editor work on the same resource.</p>
<p>In this example, we let each editor use its own memory instance of the model and synchronize on file changes only. Both frameworks already synchronize with external changes to the edited files out-of-the-box. In the glue code, a <em>org.eclipse.xtext.gmf.glue.concurrency.ConcurrentModificationObserver</em> warns the user if he/she tries to edit the same file with two different model editors concurrently.</p>
<p>In the example, we started with writing an Xtext grammar for an entity language. As explained above, we preferred optional assignments and rather covered mandatory attributes later in a validator. Into the bargain, we added some services to improve the EMF integration, namely a formatter, a fragment provider and an unloader. Then we let Xtext generate the language infrastructure. From the derived Ecore model and its generator model, we generated the edit plug-in (needed by GMF) and added some fancier icons.</p>
<p>From the GMF side, we followed the default procedure and created a gmfgraph model, a gmftool model and a gmfmap model referring to the Ecore model derived form the Xtext grammar. We changed some settings in the gmfgen model derived by GMF from the gmfmap model, namely to enable printing and to enable validation and validation decorators. Then we generated the diagram editor.</p>
<p>Voilà, we now have a diagram editor that reads/writes its semantic model as text. Also note that the validator from Xtext is already integrated in the diagram editor via the menu bar.</p>
<h3 id="gmf-integration-stage2">Stage 2: Calling the Xtext Parser to Parse GMF Labels</h3>
<p>GMF’s generated parser for the labels is a bit poor: It will work on attributes only, and will fail for cross-references, e.g. an attribute’s type. So why not use the Xtext parser to process the user’s input?</p>
<p>An <a href="https://github.com/eclipse/xtext-core/blob/master/org.eclipse.xtext/src/org/eclipse/xtext/resource/XtextResource.java">XtextResource</a> keeps track of it’s concrete syntax representation by means of a so called node model (see <a href="301_grammarlanguage.html#parser-rules">parser rules section</a> for a more detailed description). The node model represents the parse tree and provides information on the offset, length and text that has been parsed to create a semantic model element. The nodes are attached to their semantic elements by means of a node adapter.</p>
<p>We can use the node adapter to access the text block that represents an attribute, and call the Xtext parser to parse the user input. The example code is contained in <em>org.eclipse.xtext.gmf.glue.edit.part.AntlrParserWrapper</em>. <em>SimplePropertyWrapperEditPartOverride</em> shows how this is integrated into the generated GMF editor. Use the <em>EntitiesEditPartFactoryOverride</em> to instantiate it and the <em>EntitiesEditPartProviderOverride</em> to create the overridden factory, and register the latter to the extension point. Note that this is a non-invasive way to extend the generated GMF editors.</p>
<p>When you test the editor, you will note that the node model will be corrupt after editing a few labels. This is because the node model is only updated by the Xtext parser and not by the serializer. So we need a way to automatically call the (partial) parser every time the semantic model is changed. You will find the required classes in the package <em>org.eclipse.xtext.gmf.glue.editingdomain</em>. To activate node model reconciling, you have to add a line</p>
<pre><code class="language-java">XtextNodeModelReconciler.adapt(editingDomain);
</code></pre>
<p>in the method <code>createEditingDomain()</code> of the generated <em>EntitiesDocumentProvider</em>. To avoid changing the generated code, you can modify the code generation template for that class by setting</p>
<pre><code class="language-java">Dynamic Templates -&gt; true
Template Directory = "org.eclipse.xtext.example.gmf.models/templates"
</code></pre>
<p>in the <em>GenEditorGenerator</em> and</p>
<pre><code class="language-java">Required Plugins -&gt; "org.eclipse.xtext.gmf.glue"
</code></pre>
<p>in the <em>GenPlugin</em> element of the gmfgen before generating the diagram editor anew.</p>
<h3 id="gmf-integration-stage3">Stage 3: A Popup Xtext Editor (experimental)</h3>
<p><em>SimplePropertyPopupXtextEditorEditPartOverride</em> demonstrates how to spawn an Xtext editor to edit a model element. The editor pops up in its control and shows only the section of the selected element. It is a fully fledged Xtext editor, with support of validation, content assist and syntax highlighting. The edited text is only transferred back to the model if it does not have any errors.</p>
<p>Note that there still are synchronization issues, that’s why we keep this one marked as experimental.</p>
<hr />
<p><strong><a href="310_eclipse_support.html">Next Chapter: Eclipse Support</a></strong></p>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="site-footer">
<div id="extra">
<div class="inner">
<div class="container">
<div class="row">
<div class="span6">
<h3 class="footer-links-header">Quick Links</h3>
<ul class="footer-links clearfix">
<li><a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li>
<li><a href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li>
<li><a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li>
<li><a href="http://www.eclipse.org/legal/">Legal</a></li>
</ul>
<ul class="footer-links clearfix">
<li><a href="http://www.eclipse.org">Eclipse Home</a></li>
<li><a href="http://marketplace.eclipse.org/">Market Place</a></li>
<li><a href="http://www.planeteclipse.org/">Eclipse Planet</a></li>
<li><a href="https://www.eclipse.org/forums/index.php/f/27/">Xtext Forum</a></li>
</ul>
</div>
<div class="span6">
<!-- Social Media Links -->
<h3 class="footer-links-header"">Social Media</h3>
<ul class="footer-links clearfix">
<li>
<a href="https://twitter.com/xtext"><img src="/Xtext/images/Twitter-bird-darkgray.png" class="img-responsive" style="margin-right: 5px;height: 1em;" alt="Twitter icon">@xtext on Twitter</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<a href="#" class="scrollup fadeOutRight animated" style="display: none;">ScrollUp</a>
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="/Xtext/js/jquery-1.11.3.min.js"></script>
<script src="/Xtext/js/bootstrap.min.js"></script>
<script src="/Xtext/js/jquery.easing.1.3.js" type="text/javascript"></script>
<script src="/Xtext/js/jquery.prettyPhoto.js" type="text/javascript"></script>
<script src="/Xtext/js/prettify.js" type="text/javascript"></script>
<script src="/Xtext/js/lang-xtend.js" type="text/javascript"></script>
<script src="/Xtext/js/lang-common.js" type="text/javascript"></script>
<script src="/Xtext/js/custom.js" type="text/javascript"></script>
<!--script src="https://apis.google.com/js/platform.js" async defer></script-->
<!--script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push([ '_setAccount', 'UA-2429174-3' ]);
_gaq.push([ '_trackPageview' ]);
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl'
: 'http://www')
+ '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
</script-->
<script src="/Xtext/js/coverflow.min.js" type="text/javascript"></script>
<script>
$(function() {
$('#coverflow').coverflow({
active : 1,
visibleAside: 2,
overlap : 0.5,
scale : 0.9,
angle : 20,
trigger : {
"itemfocus" : true,
"swipe" : true,
"mousewheel" : false
}
});
$('#coverflow :hidden').toggle();
$(window).resize(function() {
$('#coverflow').coverflow();
});
});
</script>
</footer>
</body>
</html>