import 'ECoreUtil.eol'; | |
context EPackage { | |
constraint DiagramIsDefined { | |
check : getDiagramClass().isDefined() | |
message : 'One class must be specified as gmf.diagram' | |
} | |
constraint ContainmentReferencesAreDefined { | |
guard : self.satisfies('DiagramIsDefined') | |
check : getDiagramClass().getContainmentReferences().size() > 0 | |
message : 'Diagram class ' + getDiagramClass().name + ' must define ' | |
+ ' at least one containment reference' | |
} | |
constraint NodesAreDefined { | |
guard : self.satisfies('DiagramIsDefined') | |
check : getNodes().size() > 0 | |
message : 'No nodes (gmf.node) have been defined' | |
} | |
critique ReferenceLinksAreDefined { | |
guard : self.satisfies('DiagramIsDefined') | |
check : getReferenceLinks().size() > 0 or getLinks().size > 0 | |
message : 'No reference links (gmf.link) have been defined' | |
} | |
} | |
context EClass { | |
guard : self.isNode() | |
constraint IsValidSvgNode { | |
check : (self.getAnnotationValue('gmf.node', 'figure') = "svg") implies | |
(self.getAnnotationValue('gmf.node', 'svg.uri').isDefined()) | |
message : "No svg.uri provided for SVG figure " + self.name | |
} | |
constraint IsValidPolygonNode { | |
check : (self.getAnnotationValue('gmf.node', 'figure') = "polygon") implies | |
( | |
self.getAnnotationValue('gmf.node', 'polygon.x').isDefined() and | |
self.getAnnotationValue('gmf.node', 'polygon.y').isDefined() | |
) | |
message : "No polygon x/y coordinates provided for polygon figure " + self.name | |
} | |
constraint NodeLabelIsDefined { | |
guard : self.getAnnotationValue('gmf.node', 'label.placement') <> "none" | |
check : self.getAnnotationValue('gmf.node', 'label').isDefined() | |
message : 'No label defined for class ' + self.name | |
} | |
constraint NodeLabelsExist { | |
guard : self.satisfies('NodeLabelIsDefined') | |
check { | |
var missing : Sequence(String); | |
for (label : String in self.getAnnotationValue('gmf.node', 'label').split(',').collect(s|s.trim())){ | |
if (not self.getAttribute(label).isDefined()) { | |
missing.add(label); | |
} | |
} | |
return missing.size() = 0; | |
} | |
message : 'Label attribute(s) ' + missing.concat(', ') | |
+ ' do(es) not exist in class ' + self.name | |
} | |
} | |
context EAnnotation { | |
constraint IsValidCompartment { | |
guard : self.source = "gmf.compartment" | |
check : self.eContainer().isTypeOf(EReference) and self.eContainer().containment = true | |
message : "EReference " + self.eContainer().name + " is not a containment reference" | |
} | |
} | |
/* | |
* Validation rules for annoations details | |
*/ | |
context EStringToStringMapEntry { | |
critique IsValidLinkDecoration { | |
guard : self.is('gmf.link', 'source.decoration') or | |
self.is('gmf.link', 'target.decoration') | |
check { | |
var values := Sequence{'none', 'arrow', 'rhomb', 'filledrhomb', | |
'square', 'filledsquare', 'closedarrow', 'filledclosedarrow'}; | |
return self.value.isWithinValuesOrLooksLikeJavaClassName(values); | |
} | |
message : 'The value of ' + self.toEmfatic() + ' must be one of: ' + values.concat(', ') + | |
" or a fully-qualified Java class name" | |
} | |
critique IsValidNodeFigure { | |
guard : self.is('gmf.node', 'figure') | |
check { | |
var values := Sequence{'rectangle', 'ellipse', 'rounded', 'svg', | |
'polygon'}; | |
return self.value.isWithinValuesOrLooksLikeJavaClassName(values); | |
} | |
message : 'The value of ' + self.toEmfatic() + ' must be one of: ' + values.concat(', ') + | |
" or a fully-qualified Java class name" | |
} | |
constraint IsValidLabelPlacement { | |
guard : self.is('gmf.node', 'label.placement') | |
check { | |
var values := Sequence{'internal', 'external', 'none'}; | |
return values.includes(self.value); | |
} | |
message : 'The value of ' + self.toEmfatic() + ' must be one of: ' + values.concat(', ') | |
} | |
constraint IsValidInteger { | |
guard : self.is('gmf.node', 'border.width') or | |
self.is('gmf.node', 'margin') | |
check : self.value.isInteger() | |
message : 'The value of ' + self.key + " is not a valid integer" | |
} | |
constraint IsValidListOfIntegers { | |
guard : self.is('gmf.node', 'polygon.x') or | |
self.is('gmf.node', 'polygon.y') | |
check : self.value.matches("(\\s*\\d+)+") | |
message : 'The value of ' + self.toEmfatic() + " is not a valid list of integers" | |
} | |
constraint IsValidDimension { | |
guard : self.is('gmf.node', 'size') | |
check : self.value.matches("\\s*\\d+,\\s*\\d+\\s*") | |
message : 'The value of ' + self.toEmfatic() + " is not a valid dimension" | |
} | |
constraint IsValidRGB { | |
guard : self.is('gmf.node', 'border.color') or | |
self.is('gmf.node', 'color') or | |
self.is('gmf.link', 'color') | |
check : self.value.matches("\\s*\\d+,\\s*\\d+,\\s*\\d+\\s*") | |
message : 'The value of ' + self.toEmfatic() + " is not a valid RGB color" | |
} | |
constraint IsValidBoolean { | |
guard : self.is('gmf.diagram', 'rcp') or | |
self.is('gmf.node', 'label.icon') or | |
self.is('gmf.node', 'label.readOnly') or | |
self.is('gmf.node', 'phantom') or | |
self.is('gmf.node', 'resizable') or | |
self.is('gmf.compartment', 'collapsible') or | |
self.is('gmf.label', 'label.readOnly') | |
check { | |
var values := Sequence{'true', 'false'}; | |
return values.includes(self.value); | |
} | |
message : 'The value of ' + self.toEmfatic() + ' must be one of: ' + values.concat(', ') | |
} | |
constraint IsValidLineStyle { | |
guard : self.is('gmf.node', 'border.style') or | |
self.is('gmf.link', 'style') | |
check { | |
var values := Sequence{'dot', 'dash', 'solid'}; | |
return values.includes(self.value); | |
} | |
message : "The value of " + self.toEmfatic() + " must be one of: " + values.concat(', ') | |
} | |
constraint IsValidCompartmentLayout { | |
guard : self.key = 'layout' | |
check { | |
var values := Sequence{'list', 'free'}; | |
return values.includes(self.value); | |
} | |
message : 'The layout of the ' + self.eContainer().eContainer().name + | |
' compartment must be one of: ' + values.concat(', ') | |
} | |
} | |
context EClass { | |
guard : self.isLink() | |
constraint LinkLabelExists { | |
guard : self.getAnnotationValue('gmf.link', 'label').isDefined() | |
check { | |
var missing : Sequence(String); | |
for (label : String in self.getAnnotationValue('gmf.link', 'label').split(',').collect(s|s.trim())){ | |
if (not self.getAttribute(label).isDefined()) { | |
missing.add(label); | |
} | |
} | |
return missing.size() = 0; | |
} | |
message : 'Label attribute(s) ' + missing.concat(', ') | |
+ ' does not exist in link class ' + self.name | |
} | |
constraint LinkSourceIsDefined { | |
check : self.getAnnotationValue('gmf.link', 'source').isDefined() | |
message : 'No source defined for link class ' + self.name | |
} | |
constraint LinkSourceExists { | |
guard : self.satisfies('LinkSourceIsDefined') | |
check : self.getReference(self.getAnnotationValue('gmf.link', 'source')).isDefined() | |
message : 'No reference named ' + self.getAnnotationValue('gmf.link', 'source') | |
+ ' exists in link class ' + self.name | |
} | |
constraint LinkTargetIsDefined { | |
check : self.getAnnotationValue('gmf.link', 'target').isDefined() | |
message : 'No target defined for link class ' + self.name | |
} | |
constraint LinkTargetExists { | |
guard : self.satisfies('LinkTargetIsDefined') | |
check : self.getReference(self.getAnnotationValue('gmf.link', 'target')).isDefined() | |
message : 'No reference named ' + self.getAnnotationValue('gmf.link', 'target') | |
+ ' exists in link class ' + self.name | |
} | |
constraint LinkTargetAndSourceMustBeDifferent { | |
guard : self.satisfies('LinkSourceExists') and self.satisfies('LinkTargetExists') | |
check : self.getAnnotationValue('gmf.link', 'source') <> self.getAnnotationValue('gmf.link', 'target') | |
message : 'Source and target attributes must be different in link class ' + self.name | |
} | |
critique CanBeVisualized { | |
guard : getDiagramClass().isDefined() | |
check : getDiagramContainmentReference(self).isDefined() | |
message : 'Cannot generate link for class ' + self.name + | |
' because it cannot be contained in any containment reference' + | |
' of diagram root ' + getDiagramClass().name | |
} | |
} | |
operation String isWithinValuesOrLooksLikeJavaClassName(values : Sequence) { | |
return values.includes(self) or self.indexOf('.') > -1; | |
} | |
operation EStringToStringMapEntry is(annotation : String, key : String) { | |
return self.eContainer().source = annotation and self.key = key; | |
} | |
operation ECore!EClass getAttribute(name : String) { | |
return self.eAllStructuralFeatures.selectOne(sf:ECore!EAttribute|sf.name = name); | |
} | |
operation ECore!EClass getReference(name : String) { | |
return self.eAllStructuralFeatures.selectOne(sf:ECore!EReference|sf.name = name); | |
} | |
operation EStringToStringMapEntry toEmfatic() { | |
var s = "@" + self.eContainer.source + "(" + self.key + ")"; | |
if (self.eContainer().isKindOf(EStructuralFeature)) { | |
s = s + " of " + self.eContainer().eContainer().eContainer().name + "." + | |
self.eContainer().eContainer().name; | |
} | |
else { | |
s = s + " of " + self.eContainer().eContainer().name; | |
} | |
return s; | |
} | |
operation Any getTopEPackage() { | |
if (self.eContainer().isDefined()) { | |
return self.eContainer().getTopEPackage(); | |
} | |
else { | |
return self; | |
} | |
} |