Excerpt |
---|
...
...
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.
https://eclipse.org/modeling/emf/
Learning goals for todays exercise:
- Learn how to generate code using EMF.
- Understand how to use containment / container and regular relations in EMF.
- Learn how to instantiate your models in EMF and by Java code.
Prerequisites
- You need Eclipse Modeling Tools. Installation guidelines.
Part #1: Modelling a library.
To get a modelling kickstart, we will start using an existing domain model from a library. This model consists of the following main concepts:
Do the following to get started with this example model in your Eclipse environment:
...
supports model-driven engineering by providing a simple object-oriented modelling language for modelling data, a code generator for producing corresponding Java classes, and tools and runtime support for building views and editors for the data. |
Introduction
When building data-oriented application, you will find that some code is obviously specific for the domain, some is domain-specific but following coding patterns that make the coding pretty trivial and some is completely generic. For instance, suppose you are writing a form-based application for personell data. This will include
- writing classes for OrgUnit, Person and Role and providing get, set, add and remove methods for accessing and mutator the structure of OrgUnit, Person and Role instances
- implementing validation for attributes like name (no digits or special characters) and date of birth (no employee is 200 years old), as well as structural validation, e.g. every OrgUnit must have a Person with a manager Role
- ensuring consistency, e.g. that if a Person belongs to an OrgUnit, both objects refer to each other, and if a Person is removed from an OrgUnit, none of them refer to the other
- supporting the UI by making the domain objects observable, i.e. provide a mechanism to listen for changes
- selecting form elements based on attribute types and multiplicity
- triggering appropriate validation during editing
- persisting the data, perhaps in a file using XML or JSON format, or in a database
The accessor and mutator methods are trivial, once you know the attribute and association names and multiplicities. The validation code is domain specific, but how it is used by the UI isn't. Consistency of such opposite relations is difficult to code, but always follow the same patterns. Observability is trivial usage of coding patterns. Form element selection is rule-based, with a few options pr. type. Serializing (saving) and parsing (loading) data is a systematic and well-understood process.
We see that only part of the code is domain-specific, but it will be entangled with other code. When writing code by hand, you combine domain-specific and knowledge of coding conventions and patterns. The idea behind EMF, and model-driven development in general, is to separate the domain knowledge from the coding knowledge. The domain knowledge is captured in a domain model, while the coding knowledge (conventions, patterns, architecture, ...) is part of the framework and tools, using a combination of code generation and generic and so-called reflective code. EMF and related projects supports the following out-of-the-box:
- generate classes with accessor and mutator methods
- prevents creation of illegal or inconsistent object structures
- a validation mechanism that report which standard and custom constraints have been violated
- generic serialisation of domain data, using various popular formats
- generic and custom editors for your domain data
This relieves the developer from a lot of tedious work, but requires strong modelling skills and an understanding of how the framework utilises the model. Once mastered, it provides opportunities for developing with greater agility, efficiency and quality.
Ecore - EMF's modelling language
The core of EMF is an object-oriented modelling language called Ecore, and a supporting runtime. Ecore can be thought of as a subset of UML class diagrams (without the graphical notation), that is big enough to support basic domain modelling and small enough to allow for an efficient and lean framework. Ecore supports classes with attributes (properties of simple types), associations (references to other modelled classes) and operations, and multiple inheritance.
For more, see our Ecore page.
Ecore models may be edited using different tools and syntaxes. EMF itself provides a tree-based editor and an XML-based format (mostly for serialisation e.g. to files), EMFJSON provides a JSON format, Ecore tools (based on Sirius) provides a diagram notation and Xcore a textual syntax similar to Java classes. However, all support the same abstract language of classes, attributes, associations, operations and inheritance and any Ecore-supporting tool may use the resulting Ecore model.
For more, see our page on Editing Ecore models.
A plethora of other tools and frameworks utilise Ecore models to provide important and time-saving functionality, either part of the Eclipse Modelling project or the surrounding eco-system.
Genmodel - generating Java code
To turn an Ecore model into executable Java code, you need to configure a generator model called genmodel and run EMF's code generator. A default genmodel is provided automatically, so the only thing you normally need to do is name the Java package (prefix) of the generated Java classes. The generator may generate Java classes corresponding directly to the Ecore classes, like OrgUnit and Person. If your Ecore classes include operations, you will need to add custom code to the generated classes (methods stubs).
In addition to domain classes, you may generate an Eclipse-based editor for your model, which you can install into Eclipse to make it easier to edit your domain data.
For more, see our Genmodel page.
Validation - checking your domain data
An Ecore model will to a certain extent constrain the structure of domain objects you can create, e.g. based on the multiplicity of attributes and association. However, not all such constraints are considered hard in the sense that they are enforced by the generated classes. E.g. if an attribute's multiplicity has a lower bound of two, it will always be possible to add only one value. Instead, you may ask EMF to validate your model, and a set of diagnostic objects will tell which (if any) constraints are violated. You may add your own custom validation rules, e.g. to limit the range of integer values or characters in a String, or ensure more structural constraints are met, like an OrgUnit always having a Person with a manager Role. The generated editor will automatically use the validation mechanism to indicate violated constraints, so you can avoid illegal domain data.
For more, see our Validation page.
Persistance - storing your data
Being able to store domain data is fundamental to any application, and there are many choices for persisting Ecore-based data. EMF provides XML-based persistance of any legal structure of domain objects to file, and other projects supports other formats, e.g. EMFJSON supports JSON, and ESON a more human-friendly JSON-like syntax. There are lots of ways of tweaking the XML format used by default, or customise how the generated code handles persistance, e.g. switch to JSON or a completely custom format. In the latter case, you can implement the serialiser and parser by hand or use DSL frameworks like Xtext and EMFText to generate them from a grammar.
For more, see our Serialization page.
If you prefer persisting to a database, Teneo supports mapping Ecore models to database tables and relations (so-called Object-Relation Mapping (ORM)) using Hibernate. The CDO project also supports several relational databases. If you prefer NoSQL storage, EMFJSON supports the increasingly popular MongoDB.
Editing your data - generic and custom editors
Although you can generate a complete editor for you domain data, you will find it cumbersome to have to regenerate and reinstall it, to create and edit domain data, e.g. to provide sample data for testing. Instead you may use a so-called reflective editor, which provides generic editing support for any Ecore model without code generation. You just indicate for which model you want to create and edit data, and the editor will let you create domain objects, edit their attribute values and assemble them into object structures within the constraints of your model. This allows you to test your model immediately without generating code, e.g. instantiate domain object corresponding to a scenario and use it as initial state for test cases.
If you choose to use the generated editor as a basis for your own, custom editor, you typically will want to provide support for undo and redo. Both the generic and generated editors have primitive set/unset and add/remove operations with undo/redo support that work for any model. You can also implement custom, domain-specific operations and still have EMF handle undo and redo for you, by recording how your domain objects changes. Validation is integrated, so you can alert the user if an operation results in an invalid state.
While the editor support provided by EMF will give you functionally complete editors, they are not usable/suitable for most end-users. Better editors can of course be developed by hand, but several frameworks allow you to make good editors without a lot of coding. The EMF Forms project allows you to build a custom, form-based GUI for your domain data without coding. Instead you compose your form from layouts and editing widgets and configure how they operate on the underlying domain data. The EMF Client Platform (ECP) provides a more complete (and complex) application development framework based on the same ideas. If you prefer a diagram notation for your data, combined with some form support, or advanced tables, you can use the Sirius framework.
For more, see our page on Editing Ecore model instances.
...
Part #2: Concepts and Relations
- Find examples of EClasses and EDataTypes
- Find examples of containment / container and ordinary relations in the model.
- Try to find features properties such as:
- multiplicity – lower and upper bound
- changeable – allows being set (using setter)
- derived – computed from other values
- transient – should not be stored in external resource
- volatile – should not need to be stored in memory
- order – not used in practice, but good to know if order is important
Part #3: Extending the model
Use the model editor to add a new BookCategory. Hint: right-click on BookCategory > New Child... > Select EEnum Literal
Fill out "Literal", "Name" and "Value" properties for our new category.
Remember to save our ecore file, after the new category is added.
Part #4: Generating Java Code
First we want to validate our ecore model.
Right click on the root element and select "Validate"
When the model validates successfully, we can generate Java code from it. Properties describing what code to generate is described in a separate .genmodel file. By double clicking on the extlibrary.genmodel file you will see the following in the Properties View:
To generate Java code for our library model, right click on the root element in the editor for the .genmodel file and select Generate Model Code.
When the code generation completes successfully, you will be able to see Java code in terms of Interfaces and Classes for our library example in the package explorer:
As we see in the package explorer, each EClass "Xyz" will (by default) become one interface Xyz and one implementation class XyzImpl.
By double clicking on the BookCategory.java file you see a enum implementation where Computer Science (the modification we made to the domain model) is added as a literal object:
Part #5 Instantiating from Java
Now, with Java code for our domain model automatically generated, it is time to learn how to use and instantiate the model.
Add a new Java Project to your workspace. Give it any name, for instance "My Library Test"
In order to make use of the generated code, we need specify a dependency to the generated code.
Add a java package under the src folder and give it any useful name, for instance "edu.ntnu.mycode".
Add a new java class to this package and give it a name, for instance "TestingEMF".
Add a main-method to your class. Within the main method you can play with the generated code and create objects instantiate your first library.
Note how you use the EXTLibraryFactory.eINSTANCE to create java objects.
Part #6 Instantiating from an Editor
With the ecore model we have for the library domain, we can also use EMF to generate an editor that we can use for instantiation.
In your workspace you will also see that we have two other projects - the edit and the editor projects. These are both generated from our extlibrary.genmodel file.
The edit project contains generic reusable classes for building an editor.
The editor project contains a eclipse plugin that allow you to instantiate a library model graphically.
As we made changes in the original ecore file we should regenerate the edit and the editor projects. We generate these by right clicking on the root element in the editor for our extlibrary.genmodel. Run both "Generate Edit Code" and "Generate Editor Code".
Now, to see what this editor looks like we can open the plugin.xml file in the editor project. Under the overview tab you will find a Launch an Eclipse application link.
By pressing this link, Eclipse will fire up a new Eclipse environment with the Library editor plugin added.
In order to get started modeling instances, we need a workspace project where we can place our model files. Go into "File > New > Project" and create a general project with a name, for instance, "My Library Project".
If you right click on your new project and select "New > Other > Example EMF Model Creation Wizards", you will find an entry labeled "EXTLibrary Model". Press this link and give your model file a name, for instance "MyFirstLibrary.extlibrary". Now you need to select what kind of object you want to model. Here you can select "Library". Keep UTF-8 as encoding and press "finish".
A new .extlibrary file appears now in your project and by opening it you will be able to add children and specify model properties. The things you are able to do in this generated editor is all constrained by the structure of your original ecore file.
Other Eclipse projects (like Sirius) allow you to customize and generate event cooler and more graphical editors for your domain.