context NamedElement { -- Every NamedElement must define a name constraint HasName { check : self.name <> '' message : 'Element ' + self + ' must define a name' } } context Feature { -- The name of a feature (attribute,referecne,parameter) -- should start with a lower case letter critique NameMustStartWithLowerCase { guard : self.satisfies('HasName') check : self.name.substring(0,1) = self.name.substring(0,1).toLowerCase() } } context Class { -- The name of a class should start with -- an upper case letter critique NameShouldStartWithUpperCase { guard : self.satisfies('HasName') check : self.name.substring(0,1) = self.name.substring(0,1).toUpperCase() message : 'The name of class ' + self.name + ' should start with an upper-case letter' fix { title : 'Rename class ' + self.name + ' to ' + self.name.firstToUpperCase() do { self.name := self.name.firstToUpperCase(); } } } -- A class must not directly or indirectly -- inherit from itself constraint MustNotInheritItself { check : not self.inherits(self) message : 'Class ' + self.name + ' inherits itself' } -- A class is unused when it is not the type of a feature -- or a parameter and is not extended by another class critique UnusedClass { check : Parameter.allInstances.exists(p|p.type = self) or Feature.allInstances.exists(f|f.type = self) or Class.allInstances.exists(c|c."extends" = self) message : 'Unused class ' + self.name fix { title : 'Delete class ' + self.name do { delete self; } } } } -- Returns if a class directly or indirectly -- inherits from another class operation Class inherits(c : Class) : Boolean { if (self."extends".isDefined()) { return self."extends" = c or self."extends".inherits(c); } else { return false; } }
@namespace(uri="OO", prefix="OO") package OO; class Model extends Package { } abstract class PackageableElement extends NamedElement { ref Package#contents ~package; } abstract class AnnotatedElement { val Annotation[*] annotations; } class Annotation { attr String key; attr String value; } abstract class NamedElement extends AnnotatedElement { attr String name; } class Package extends PackageableElement { val PackageableElement[*]#~package contents; } abstract class ~Classifier extends PackageableElement { } class ExternalClass extends ~Class { } class ~Class extends ~Classifier { ref ~Class#extendedBy ~extends; ref ~Class[*]#~extends extendedBy; val Feature[*]#owner features; attr Boolean isAbstract; } class Datatype extends ~Classifier { } abstract class Feature extends NamedElement { ref ~Class#features owner; ref ~Classifier type; attr VisibilityEnum visibility; } abstract class StructuralFeature extends Feature { attr Boolean isMany; } class Operation extends Feature { val Parameter[*]#owner parameters; } class Parameter extends NamedElement { ref ~Classifier type; ref Operation#parameters owner; } class Reference extends StructuralFeature { } class Attribute extends StructuralFeature { } enum VisibilityEnum { public = 1; private = 2; }
There are two ways to get the code of this example:
Once you have checked out/imported the code, to run the example you need to go through the following steps:
In this example, we use the Epsilon Validation Language (EVL), to express constraints for models that conform to the OO.emf metamodel.
.emf files are Ecore metamodels expressed using the Emfatic textual syntax.
More examples are available in the examples folder of the SVN repository.