Documentation

ETModelElementDescription class documentation

ETModelElementDescription : NSObject

Abstract base class used by Model Description core classes.

AuthorsGenerated by qmathe
Declared inETModelElementDescription.h

Overview

The Model Description classes implement a Metamodel framework inspired by FAME (http://scg.unibe.ch/wiki/projects/fame).

Within this Metamodel, ETModelElementDescription provide basic abilities:

ETEntityDescription, ETPropertyDescription and ETPackageDescription all inherit from ETModelElementDescription. A model element description can be registered inside a model description repository using -[ETModelDescriptionRepository addDescription:] .

Conceptual Model

This metamodel is based on the [FM3 specification](http://scg.unibe.ch/wiki/projects/fame/fm3).

For a good introduction, read the paper [FAME — A Polyglot Library for Metamodeling at Runtime](http://www.iam.unibe.ch/~akuhn/d/Kuhn-2008-MRT-Fame.pdf)

We support the entire FM3 specification with some minor adjustements, however the tower (model, metamodel, meta-metamodel) is not explicitly modeled in the API unlike in FAME.

The MSE serialization format is also unsupported. In the future, we will provide our own exchange format based on JSON.

FAME Terminology Change Summary

Those changes were made to further simplify the FAME terminology which can get obscure since it overlaps with the host language object model, prevent any conflict with existing GNUstep/Cocoa API and reuse GNUstep/Cocoa naming habits.

We list the FAME term first, then its equivalent name in EtoileFoundation:

FM3.Element
ETModelElementDescription
FM3.Class
ETEntityDescription
FM3.Property
ETPropertyDescription
FM3.RuntimeElement
ETAdaptiveModelObject
attributes (in Class)
propertyDescriptions (in ETEntityDescription)
allAttributes (in Class)
allPropertyDescriptions (in ETEntityDescription)
superclass (in Class)
parent (in ETEntityDescription)
package (in Class)
owner (in ETEntityDescription)
class (in Property)
owner (in ETPropertyDescription)

For the last two points, we can consider FM3.Property.class and FM3.Class.package have been merged into a single FM3.Element.owner property in EtoileFoundation since they were redundant.

Changes to FAME

In EtoileFoundation, there is a -owner property that represents either:

While in FAME, owner is a derived property and these various owner kinds are each modeled using a distinct property (class in FM3.Property and package in FM3.Class).

In FAME, container implies not multivalued. In EtoileFoundation, multivalued now controls whether a property is a container or not, and -isContainer is now derived.

Unlike FAME, EtoileFoundation does support overriding property descriptions. This is mainly useful, for read-only properties overriden as read-write in subclasses/subentities.

Additions to FAME

-isPersistent has been added to control the persistency, how the interpret the metamodel and its constraints for the framework providing the persistent support is up to this framework. For now, some CoreObject constraints are harcoded in the metamodel.

-isReadOnly has been added to support set-once properties.

-itemIdentifier has been added as a mean to get precise control over the UI generation with EtoileUI.

Removals to FAME/EMOF

NamedElement and NestedElement protocols don't exist explicitly.

Property description names can be in upper case (FAME was imposing lower case as a constraint).

Metamodel Constraint Summary

Metamodel constraints are checked in -checkConstraints: , while model constraints are validated in -[ETPropertyDescription validateValue:forKey:] .

Note: In the future, -checkConstraints: should probably be delegated to -[ETPropertyDescription validateValue:forKey:] in the meta-metamodel

If we sum up the changes to the FAME conceptual model, for the new ETPropertyDescription, the metamodel constraints are:

  • composite is derived from opposite.container
  • derived and not multivalued implies container
  • derived implies not persistent
  • if set, opposite.opposite must be self (i.e. opposite properties must refer to each other)
  • if set, opposite.owner must be type
  • owner must not be nil
  • type must not be nil

At the model level, the semantics are:

  • container property chains may not include cycles
  • opposite properties must refer to each other
  • any multivalued property defaults to empty
  • boolean properties default to false
  • non primitive properties default to nil
  • string and number properties do not have a default value (could be changed later)

Note: The two first points are model constraints, but -[ETPropertyDescription validateValue:forKey:] doesn't check them.

Since the metamodel is the model of the meta-metamodel, the model semantics apply to the metamodel too.

For the new ETEntityDescription, the metamodel constraints are:

  • parent is not nil
  • parent must not be a primitive, unless self is a primitive
  • parent chain may not include cycles (could be removed, this comes from 'container property chains may not include cycles' in the model semantics of ETPropertyDescription)
  • package must not be nil
  • allPropertyDescriptions is derived as union of propertyDescription and parent.allPropertyDescriptions
  • elements in propertyDescriptions override identically named elements from parent.propertyDescriptions in allPropertyDescriptions
  • allPropertyDescriptions must have unique names

Discussion of Composite and Aggregate Terminology in UML

To recap the relationship types from UML:

association
a relationship between two objects with no additional constraints.
aggregation
a type of association, with the constraint that all of the pointers in an object graph belonging to aggregation relationships form a DAG (this doesn’t preclude the relationship being many:many). Aggregation represents a whole-part relationship, and descendent objects in this DAG can be considered a “part of” all of their ancestors.
composition
a type of aggregation, with the additional constraint that an object can only have one composite pointer to it at a time (across all incoming relationships).

I think these definitions are complete, but for more info, see "association", "aggregate", and "composite" in “The Unified Modeling Language Reference Manual”. Note that aggregation and composite are just restrictions on the object graph, and they are orthogonal to relationship cardinality (one:one, one:many, many:many), although composite relationships can’t be many:many as a consequence of the definition of composite.

CoreObject implements a subset of the UML design with some of our own restrictions: If a relationship is many:many, we add no additional constraints (it’s a UML association). If a relationship is one:many or one:one, and bidirectional, we treat it as a UML aggregation. Note that CoreObject doesn’t support UML the composition constraint described above. Unfortunately the CoreObject source code uses the term “composite” a lot in ways that don’t match UML.

Also note that an UML aggregation relationship with a one:one/many constraint is similar to UML composition; the only difference is that UML composition adds the additional constraint that the object can have only one incoming composite reference across all of its relationships.

It could be worth supporting the full UML model, or supporting FAME’s model, because CoreObject’s current model is a bit weird in that relationship cardinality determines object graph constraints (association, aggregation, composition). For example, in CoreObject it’s impossible to model associations that are one:one or one:many, but are not aggregations (so you want to allow cycles). It’s also strange that a relationship in CoreObject can only be aggregation if it’s also bidirectional, this should probably be changed. However, I'm not sure about these points; any changes need to be carefully considered, especially with respect to COCopier.

Composite and Aggregate in FAME

FAME lacks the aggregation/composition distinction, it only has composition. Composition in FAME is almost the same as UML (no cycles in the pointers making up composite relationships between objects, plus every object can only have a single incoming composite pointer). For the second condition, FAME is slightly stricter in that a Class can only have a single incoming composite relationship, whereas UML permits multiple incoming composite relationships as long as only one of them is non-NULL at a time (roughly speaking, UML puts the constraint at runtime, FAME puts the constraint at compile time).


Metamodel Description

+ (ETEntityDescription *) newEntityDescription

Returns a new self-description (aka meta-metamodel).

    Initialization

    + (id) descriptionWithName: (NSString *)name

    Returns an autoreleased entity, property or package description.

    See also -initWithName: .

      - (id) initWithName: (NSString *)name

      Initializes and returns an entity, property or package description.

      You must only invoke this method on subclasses, otherwise nil is returned.

      You should pass the property name in argument for a property description. And the class name for an entity description, the only exception is when the entity description applies to a prototype rather than a class.

      Raises an NSInvalidArgumentException when the name is nil or already in use.

        - (id) init

        Initializes and returns entity, property or package description whose name is Untitled.

          Querying Type

          - (BOOL) isPropertyDescription

          Returns whether the receiver describes a property.

            - (BOOL) isEntityDescription

            Returns whether the receiver describes an entity.

              - (BOOL) isPackageDescription

              Returns whether the receiver describes a package.

                Basic Model Specification

                - (NSString *) name

                The name of the entity, property or package.

                  - (void) setName: (NSString *)name

                  The name of the entity, property or package.

                    - (NSString *) fullName

                    Returns the name that uniquely identify the receiver.

                    The name is a key path built by joining every names in the owner chain up to the root owner. The key path pattern is: ownerName*.receiverName.

                    The + sign indicates ownerName can be repeated zero or multiple times.

                    Given a class Movie and its property director. The full names are:

                    • Movie for the class
                    • Movie.director for the property
                      - (id) owner

                      Returns the element that owns the receiver.

                      For a property, the owner is the entity it belongs to.

                      For an entity, there is no owner, unless the entity belongs to a package.

                      For a package, there is no owner.

                      By default, returns nil.

                        - (BOOL) isMetaMetamodel

                        Wether the receiver describes an object that belongs to the metamodel.

                          - (void) setIsMetaMetamodel: (BOOL)isMetaMetamodel

                          Wether the receiver describes an object that belongs to the metamodel.

                            Model Presentation

                            - (NSString *) displayName

                            A short and human-readable name e.g. Person, Music Track, Anchor Point.

                            This is used to present the entity, property or package localized name to the user in the UI.

                            By default, returns -name that is not localized, but in a capitalized and spaced version. For an ETEntityDescription, the type prefix is removed (if +[NSObject typePrefix] returns a valid value). For example, ETMusicTrack is returned as Music Track.

                            You can override this built-in display name by setting a custom one.

                              - (void) setDisplayName: (NSString *)displayName
                              Description forthcoming.
                                - (NSString *) typeDescription

                                Returns a short and human-readable description of the receiver type.

                                It must be derived from the class name. e.g. Package for ETPackageDescription.

                                By default, returns Element.

                                  - (NSString *) itemIdentifier

                                  The hint that precises how the receiver should be rendered e.g. at UI level.

                                  You can use this hint to identify which object to ouput, every time a new representation has to be generated based on the description.

                                  ETModelDescriptionRenderer in EtoileUI uses it to look up a template item that will represent the property at the UI level.

                                  By default, returns nil.

                                    - (void) setItemIdentifier: (NSString *)itemIdentifier

                                    The hint that precises how the receiver should be rendered e.g. at UI level.

                                    You can use this hint to identify which object to ouput, every time a new representation has to be generated based on the description.

                                    ETModelDescriptionRenderer in EtoileUI uses it to look up a template item that will represent the property at the UI level.

                                    By default, returns nil.

                                      Runtime Consistency Check

                                      - (void) checkConstraints: (NSMutableArray *)warnings

                                      Checks the receiver conforms to the FM3 constraint spec and adds a short warning to the given array for each failure.

                                      A warning must be a NSString instance that describes the issue. Every warning should be created with -warningWithMessage: .

                                        - (NSString *) warningWithMessage: (NSString *)msg

                                        Returns an autoreleased warning built with the given explanation.

                                        See -checkConstraints: .

                                          Internal

                                          - (void) checkNotFrozen

                                          Throws an exception if the frozen flag is YES. This should be called in ETModelElementDescription and subclasses before every mutation.

                                            - (void) makeFrozen

                                            Marks the receiver as frozen. From this point, the receiver is immutable and any attempt to mutate it will cause an exception to be thrown.