Ecore is EMF's object-oriented modelling language, and supports 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.
There can be many perspectives on modelling, traditionally UML class diagrams have been used for both analysis and design, i.e. describing the concepts in the domain as perceived by stakeholders and describing the software solution. When building an Ecore model, there are typically two perspectives that are relevant:
- With a code-centric perspective, you create Ecore classes with the features needed for the generator to generate the desired Java classes, fields and methods.
- With a runtime-perspective, you think of the Ecore classes as a way of constraining the object structures that are allowed during runtime.
When describing Ecore's modelling constructs below, we will take the latter of these perspectives. For the code perspective, see Genmodel.
Main modelling elements
Ecore supports classes with attributes (properties of simple types), associations (references to other modelled classes) and operations, and multiple inheritance. The main construct is the class, which is called EClass in Ecore terminology. An EClass contains (structural) features, which are either attributes or references (one-way associations) and operations, and can be related to other classes through inheritance.
|Construct||Runtime instance structures|
Abstract superclass of EClass and EDataType
The class construct, has a name and can be abstract (cannot be instantiated) and also marked as interface (no state, just methods). A container of so-called structural features (attributes and associations). May have a list of superclasses (EClass).
Non-abstract classes can be instantiated. Instances will have attributes values and links to other objects corresponding to contained and inherited features.
A non-modelled or "foreign" type, provided by the host language and runtime environment, like int, double, String, Date etc. Many such types are pre-defined by Ecore, e.g. EInt, EIntegerObject, EDouble, EDoubleObject, EBoolean, EBooleanObject, EString, EDate corresponding to Java's int, Integer, double, Double, boolean, Boolean, String and Date types. You can define your own, to be able to use other Java types in your model.
|Instances of the corresponding (non-abstract) Java classes can be created from Strings.|
A special kind of EDataType, where you list the set of (possible) literal values. It's similar to a simple Java enum, and a Java enum will be generated.
|Instances of a generated Java enum class, that are more like values than object instances.|
Abstract superclass of EAttribute and EReference. The distinction between these two is the kind of type they have, EDataType and EClass, respectively, so when adding a "property" to a class you decide which of EAttribute and EReference to use based on whether the type is an EDataType or EClass.
An EStructuralFeature has a name, type (an EDataType) and multiplicity (lower and upper bounds).
An EStructuralFeature where the type is an EDataType.
or using inheritance
Both OrgUnit and Person instances have a name attribute.
An EStructuralFeature where the type is an EClass. Corresponds to the target role of an association from the owning EClass to a target EClass. The association itself is not explicitly modelled.
Two EReferences may be each other's opposite, meaning they correspond to roles of the logically same association. This implies the consistency requirement that if one instance refers to another, the other must refer back, and vice versa.
Consistency requirement: Since o1 has workers links to p1 and p2, p1 and p2 must both have a works-in link to o1.
EReferences can be marked as containment or container, to support creating strict hierarchies. A containment reference points down the hierarchy and a container reference points up. Often you have containment and container references in pairs that are each others opposites. An object can only be directly contained in one container, and this is enforced. If we model the workers EReference as containment, meaning a Person belongs to only one OrgUnit, the opposite worksIn EReference is automatically marked as container.
In general you want objects structures to be hierarchies with one root, hence containment and container markings are important. Usually you want to ensure that every class has a container EReference, unless you consider it a root object in the hierarchy.
Corresponds to methods. Includes return type (EClassifier), typed (EClassifier) parameters and a list of types it may throw (EDataType).
The classes and data types (EClassifiers) in an Ecore model must be inserted into an EPackage as its classifiers. Hence, an Ecore model will consist of one or more EPackages containing EClasses and EDataTypes. The EPackage has a name and an identifier (nsUri), the latter must be globally unique, and typically is or includes the identifier of the software module (e.g. Eclipse plugin, OSGi bundle or maven module) containing the model. One possibility is using a so-called platform URI, which is a special URI used in Eclipse to identify a file in your workspace. E.g. platform:/plugin/no.hal.tdt4250/model/model.ecore refers to the model.ecore file in the model directory in the no.hal.tdt4250 project, and could be used as the unique identifier for the EPackage in that Ecore model. Take care when deciding on the name and nsUri as these will be used by tools. E.g. the name is used by the code generator as the last element of the Java package for the generated classes, and the nsUri is used for looking up the package in a global registry.
Ecore includes a mechanism for attaching extra data to all the above modelling elements, in the form of String key-value pairs. The extra data is typically used by tools, e.g. annotations are used for naming constraints (that will need to be implemented by hand in the generated code, see Constraints and validation) and providing method bodies for the code generator. You may also add your own custom annotations that are utilised by your own tools.
An annotation is added as an EAnnotation object to a model element, and its source attribute is used as a qualifier to identify its meaning/purpose. This qualifier is typically an URI or qualified name that identifies the tool that uses it. E.g. to use Ecore-specific annotation you use http://www.eclipse.org/emf/2002/Ecore as the source attribute value. The annotation data are added as key-value pairs and value in the annotation's details map.
Model elements as meta-objects
When you build an Ecore model, whether using the tree-based editor, Ecore tools diagram editor or Xcore text editor, you are actually building an object structure, a structure of so-called meta-objects (meta because they are at a conceptual level above the instances of the classes they model). E.g. in the example above, OrgUnit and Person are instances of the EClass, the name attribute is an instance of EAttribute and the workers and works-in references are instances of EReference. The figure below shows the standard class diagram notation (left) and the corresponding object diagram of the meta-objects (right).
|Class diagram||Object diagram of meta-objects|
There's a lot of detail in such a diagram, and all of them have to be right for the generated code to work as intended. A good editor helps a lot (see Editing Ecore models).