context OO!NamedElement {
// Every NamedElement must define a name
constraint HasName {
check : self.name <> ""
message : "Element " + self + " must define a name"
}
}
context OO!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 OO!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;
}
Check out the code from the SVN:
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 EVL, to express constraints for models that conform to an Object-Oriented metamodel.
.emf files are Ecore metamodels expressed using the Emfatic textual syntax.
More examples are available in the examples folder of the SVN repository.