/*Title: Tefkat trnasformation rules between Ecore and Object-Z
* Author: Soon-Kyeong Kim
* Last Modified: 28 February 2006
*
* Information Technology and Electrical Engineering
* The University of Queensland, St. Lucia, 4072, Australia
*
*/
TRANSFORMATION EcoretoOZ : Ecore -> ObjectZ
IMPORT http:///ecoreTracking
IMPORT http:///oz.ecore
IMPORT http://www.eclipse.org/emf/2002/Ecore
//IMPORT http://www.itee.uq.edu.au/~mdavv/1.0.0/oz.ecore
// Produces an OZ specification for each Ecore package (root of OZ spec)
//
RULE EPackage2OZSpec(ep, ozs)
FORALL EPackage ep
MAKE OZSpecification ozs
SET ozs.name = ep.name
LINKING EPackOZSpec
WITH ozspec = ozs, epack = ep
;
// Mapping Ecore types to OZ types
// For ecore data types (except enumeration types and
// those predefined data types that have corresponding data types in OZ, e.g.
// EInt, EBoolean, EFloat)
// makes a given type in OZ.
RULE EOtherDataType2OZOtherType(et, gt, ozs, ep)
FORALL EDataType et
WHERE EPackOZSpec LINKS ozspec = ozs, epack = ep
AND NOT isEEnum(et)
//need to check all otherpredefined ecore types
AND NOT isEClassType(et)
AND ep.eClassifiers = et
MAKE GivenType gt
SET gt.name = et.name, gt.owner = ozs
LINKING EDataTypeOZOtherType
WITH other = gt, edata= et, ozspec = ozs, epack = ep
;
// Maps ecore enumeration types to OZ free types
//
RULE EEnum2OZFreeType(ft, et, ozs, ep)
FORALL EEnum et
WHERE EPackOZSpec LINKS ozspec = ozs, epack = ep
AND ep.eClassifiers = et
MAKE FreeType ft
SET ft.name = et.name, ft.owner = ozs
LINKING EEnumFreeType
WITH free = ft, enum = et, ozspec = ozs, epack = ep
;
// Maps ecore enumeration literals to OZ free type braches
//
RULE EEnumLiteral2OZBranch(el, br, ozf, ee)
FORALL EEnumLiteral el
WHERE EEnumFreeType LINKS free = ozf, enum = ee
AND ee.eLiterals = el
MAKE Branch br
SET br.name = el.name, br.freetype = ozf
//br.name = el.value
LINKING EEnumLiteralBranch
WITH branch = br, eliteral = el, free = ozf, enum = ee
;
// Patterns to check types of Ecore elements
//
PATTERN isEClassType(etype)
FORALL EClass etype;
PATTERN isEDataType(etype)
FORALL EDataType etype;
PATTERN isEEnum(etype)
FORALL EEnum etype;
// Produces a Class for each Ecore class
//
RULE EClass2OZClass(ep, ozs, ozc, ec, com)
FORALL EClass ec
WHERE EPackOZSpec LINKS ozspec = ozs, epack = ep
AND ep.eClassifiers = ec
MAKE OZClass ozc
SET ozc.name = ec.name, ozc.owner = ozs,
IF isAbstract(ec) THEN MAKE OZComment com, OZExpression exp, OZPredicate pre
SET //constain formalizing the abstract class concept in UML
exp.name = "ECore abstract class",
com.body = "ECore abstract class",
ozc.comment = com,
exp.body = append(ozc.name, " = \\emptyset"),
pre.specification = exp, ozc.invariant = pre
ENDIF
LINKING EClassOZClass
WITH ozclass = ozc, eclass = ec, ozspec = ozs, epack = ep
;
// Maps Ecore supertypes to the general class set of the correspoing OZ class
//
RULE ESuperType2OZInherit(ec, ozs, ozg, est)
FORALL EClass ec, EClass est
WHERE lookupClass(ozs, ec)
AND lookupClass(ozg, est)
AND ec.eSuperTypes = est
SET ozs.general = ozg
;
// Pattern to lookup classes
//
PATTERN lookupClass(ozc, ec)
WHERE EClassOZClass LINKS ozclass = ozc, eclass = ec
;
// Pattern to map parameter kinds
//
PATTERN lookupParamKind(ozparkind)
WHERE ozo =
AND ozparkind = ozo.instance
;
// Produces an OZ operation for each Ecore Operation
// Also produces a return paramter for each Ecore Operation
// This is because in Ecore, operations are a typed element including
// the semantics of a return parameter as part of the operation semanitcs
RULE EOperation2OZOperation(ec, ozc, ozo, eo, ep, ozop, ozs, epa)
FORALL EOperation eo
WHERE lookupClass(ozc, ec)
AND ec.eOperations = eo
AND EPackOZSpec LINKS ozspec = ozs, epack = epa
AND EClassOZClass LINKS ozclass = ozc, eclass = ec, ozspec = ozs, epack = epa
AND lookupParamKind(ozpkind)
AND et = eo.eType
MAKE OZOperation ozo, OZParameter ozp
SET ozo.name = eo.name, ozc.operation = ozo,
//mapping properties to the return parameter
ozp.name = eo.name,
ozp.isOrdered = eo.ordered,
ozp.lower = eo.lowerBound, ozp.upper = eo.upperBound,
ozp.owner = ozo,
//mapping parameter kind as output
ozp.kind = ozpkind,
IF lookupType(ozt, et) THEN
SET ozp.type = ozt
ENDIF,
//If the class type is abstract, set the isPolymorphic feature of the OZ attribute true
IF isEClassType(et) AND isAbstract(et) THEN
SET ozp.isPolymorphic = true
ENDIF,
//From Ecore to OZ, we need to create datatypes in each instance model
//From OZ to Ecore, we can map OZ types to Ecore predefined data types.
//Creates an OZ basic type for Ecore EInt, EFloat and EBoolean types
IF et.name = "EInt" OR et.name = "EFloat" OR et.name = "EBoolean" THEN
MAKE println("test", et.name), BasicType bt FROM basicTypeFromEcoreType(et.name)
SET IF (et.name = "EInt") THEN SET bt.name = "Integer", ozp.type = bt
ELSEIF (et.name = "EFloat") THEN SET bt.name = "Real", ozp.type = bt
ELSEIF (et.name = "EBoolean") THEN SET bt.name = "Boolean", ozp.type = bt
ENDIF,
ozs.type = bt
LINKING EDataTypeBasicType
WITH basic = bt, edata= et, ozspec = ozs, epack = epa
ENDIF,
//Creates an OZ given type if the type is not Ecore EInt, EFloat and EBoolean types
IF NOT (isEEnum(et) OR isEClassType(et) OR et.name = "EInt" OR et.name = "EFloat" OR
et.name = "EBoolean") THEN
MAKE GivenType gt FROM givenTypeFromEcoreType(et.name)
SET gt.name = et.name, ozp.type = gt,
ozs.type = gt
LINKING EDataTypeOZOtherType
WITH other = gt, edata= et, ozspec = ozs, epack = epa
ENDIF
// LINKING EParameterOZParameter
// WITH ozop = ozo, eop = eo, ozpar = ozp, epar = ep
LINKING EOpOZOp
WITH ozop = ozo, eop = eo, ozclass = ozc, eclass = ec
;
// Pattern to map enumeration or class types
//
PATTERN lookupType(ozt, et)
WHERE EEnumFreeType LINKS free = ozt, enum = et
OR EClassOZClass LINKS ozclass = ozt, eclass = et
;
// Produces an OZ Parameter for each Ecore Parameter
//
RULE EParam2OZParam(ozo, eo, ozp, ep, ozt, et, ec, oc, ozs, epa)
FORALL EParameter ep
WHERE EOpOZOp LINKS ozop = ozo, eop = eo, ozclass = ozc, eclass = ec
AND EPackOZSpec LINKS ozspec = ozs, epack = epa
AND EClassOZClass LINKS ozclass = ozc, eclass = ec, ozspec = ozs, epack = epa
AND eo.eParameters = ep
AND et = ep.eType
MAKE OZParameter ozp
SET ozp.name = ep.name,
ozp.isOrdered = ep.ordered,
ozp.lower = ep.lowerBound, ozp.upper = ep.upperBound,
ozp.owner = ozo,
IF lookupType(ozt, et) THEN
SET ozp.type = ozt
ENDIF,
//If the class type is abstract, set the isPolymorphic feature of the OZ attribute true
IF isEClassType(et) AND isAbstract(et) THEN
SET ozp.isPolymorphic = true
ENDIF,
//From Ecore to OZ, we need to create datatypes in each instance model
//From OZ to Ecore, we can map OZ types to Ecore predefined data types.
//Creates an OZ basic type for Ecore EInt, EFloat and EBoolean types
IF et.name = "EInt" OR et.name = "EFloat" OR et.name = "EBoolean" THEN
MAKE println("test", et.name), BasicType bt FROM basicTypeFromEcoreType(et.name)
SET IF (et.name = "EInt") THEN SET bt.name = "Integer", ozp.type = bt
ELSEIF (et.name = "EFloat") THEN SET bt.name = "Real", ozp.type = bt
ELSEIF (et.name = "EBoolean") THEN SET bt.name = "Boolean", ozp.type = bt
ENDIF,
ozs.type = bt
LINKING EDataTypeBasicType
WITH basic = bt, edata= et, ozspec = ozs, epack = epa
ENDIF,
//Creates an OZ given type if the type is not Ecore EInt, EFloat and EBoolean types
IF NOT (isEEnum(et) OR isEClassType(et) OR et.name = "EInt" OR et.name = "EFloat" OR
et.name = "EBoolean") THEN
MAKE GivenType gt FROM givenTypeFromEcoreType(et.name)
SET gt.name = et.name, ozp.type = gt,
ozs.type = gt
LINKING EDataTypeOZOtherType
WITH other = gt, edata= et, ozspec = ozs, epack = epa
ENDIF
LINKING EParameterOZParameter
WITH ozop = ozo, eop = eo, ozpar = ozp, epar = ep
;
// Produces an OZ attribute for each Ecore attribute
//
RULE EAttribute2OZPureAttribute(ozc, ec, et, oza, ea, ozt, ozot, ep, ozs)
FORALL EAttribute ea
WHERE lookupClass(ozc, ec)
AND EPackOZSpec LINKS ozspec = ozs, epack = ep
AND EClassOZClass LINKS ozclass = ozc, eclass = ec, ozspec = ozs, epack = ep
AND ec.eAttributes = ea
AND ea.eAttributeType = et
AND ozs.type = ozc
AND ep.eClassifiers = ec
MAKE PureAttribute oza, println("test", et.name)
SET oza.name = ea.name, oza.owner = ozc,
//mapping multiplicity feature
oza.lower = ea.lowerBound, oza.upper = ea.upperBound,
//mapping ordered feature
oza.isOrdered = ea.ordered,
//mapping changeability feature in ecore
IF (ea.changeable = true) THEN
SET oza.isConstant = false
ELSEIF oza.isConstant = true
ENDIF,
//mapping derived feature in ecore
oza.isSecondary = ea.derived,
//mapping type
IF lookupType(ozt, et) THEN
MAKE println("test", ozt.eClass().name, ozt.name, et.name)
SET oza.type = ozt
ENDIF,
//mapping initial values
IF isDefaultValue(ea.defaultValueLiteral)
THEN MAKE OZExpression initial
SET initial.body = ea.defaultValueLiteral,
oza.initialValue = initial
ENDIF,
//Creates an OZ basic type for Ecore EInt, EFloat and EBoolean types
IF et.name = "EInt" OR et.name = "EFloat" OR et.name = "EBoolean" THEN
MAKE println("test", et.name), BasicType bt FROM basicTypeFromEcoreType(et.name)
SET IF (et.name = "EInt") THEN SET bt.name = "Integer", oza.type = bt
ELSEIF (et.name = "EFloat") THEN SET bt.name = "Real", oza.type = bt
ELSEIF (et.name = "EBoolean") THEN SET bt.name = "Boolean", oza.type = bt
ENDIF,
ozs.type = bt
LINKING EDataTypeBasicType
WITH basic = bt, edata= et, ozspec = ozs, epack = ep
ENDIF,
//Creates an OZ given type if the type is not Ecore EInt, EFloat and EBoolean types
IF NOT (isEEnum(et) OR isEClassType(et) OR et.name = "EInt" OR et.name = "EFloat" OR
et.name = "EBoolean") THEN
MAKE GivenType gt FROM givenTypeFromEcoreType(et.name)
SET gt.name = et.name, oza.type = gt,
ozs.type = gt
LINKING EDataTypeOZOtherType
WITH other = gt, edata= et, ozspec = ozs, epack = ep
ENDIF
LINKING EAttributeOZPureAttribute
WITH ozatt = oza, eatt = ea, ozclass = ozc, eclass = ec
;
// Pattern to check the existence of initial values
//
PATTERN isDefaultValue(exp)
FORALL EString exp
;
// Pattern to check abstract classes
//
PATTERN isAbstract(ec)
FORALL EClass ec
WHERE ec.abstract = true
;
// Pattern to check the existence of Ecore opposite
//
PATTERN isEOpposite(eop)
FORALL EReference eop
;
PATTERN hasEOpposite(er)
FORALL EReference er, EReference eop
WHERE er.EOpposite = eop
;
// Produces an OZ relationship attribute for each Ecore reference
//
RULE EReferences2OZRelAttr(ozc, ot, ec, ozra, er, et)
FORALL EReference er
WHERE lookupClass(ozc, ec)
AND ec.eReferences = er
// convert attribute type
AND er.eReferenceType = et
MAKE RelationshipAttribute ozra
SET ozra.name = er.name, ozra.owner = ozc,
//mapping multiplicity feature
ozra.lower = er.lowerBound, ozra.upper = er.upperBound,
//mapping ordered feature
ozra.isOrdered = er.ordered,
// mapping containment feature
ozra.isContainment = er.containment,
//mapping changeability feature
IF (er.changeable = true) THEN
SET ozra.isConstant = false
ELSEIF ozra.isConstant = true
ENDIF,
//mapping derived feature
ozra.isSecondary = er.derived,
//mapping types
IF lookupType(ozt, et) THEN
MAKE println("test", er.eContainingClass.name, er.name, er.lowerBound, er.upperBound, er.eOpposite.name, er.eOpposite.lowerBound, er.eOpposite.upperBound)
SET ozra.type = ozt
ENDIF,
//checking abstract classes and making the relationship attribute polimorphic
IF isAbstract(et) THEN
SET ozra.isPolymorphic = true
ENDIF,
//mapping initial values
IF isDefaultValue(er.defaultValueLiteral)
THEN MAKE OZExpression initial
SET initial.body = er.defaultValueLiteral,
ozra.initialValue = initial
ENDIF,
//mapping eOpposite
//prodiuces constraints formalizing the object references according to the properties of the eOpposite
//
IF isEOpposite(er.eOpposite) THEN
MAKE println("test EPoosite", er.eContainingClass.name, er.name, er.lowerBound, er.upperBound, er.eOpposite.name, er.eOpposite.lowerBound, er.eOpposite.upperBound),
OZExpression exp, OZPredicate pre, OZComment com
SET exp.name = "ECore eOpposite", com.body = "ECore eOpposite", exp.comment = com,
// 1 to 1 relationship
IF (er.lowerBound = 1 AND er.upperBound = 1 AND er.eOpposite.lowerBound = 1 AND er.eOpposite.upperBound = 1) THEN
SET exp.body = append("\\self = ", ozra.name, ".", er.eOpposite.name)
ENDIF,
// 1 to many relationship not ordered
IF (er.lowerBound = 1 AND er.upperBound = 1 AND NOT er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = false
THEN
SET exp.body = append("\\self \\in ", ozra.name, ".", er.eOpposite.name)
ENDIF,
// 1 to many relationship ordered
IF (er.lowerBound = 1 AND er.upperBound = 1 AND NOT er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = true
THEN
SET exp.body = append("\\self \\in \\ran(", ozra.name, ".", er.eOpposite.name, ")")
ENDIF,
// not ordered many to 1 relationship
IF er.ordered = false
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND er.eOpposite.lowerBound = 1
AND er.eOpposite.upperBound = 1
THEN
SET exp.body = append("\\forall o: ", ozra.name, " @ ", "\\self = o.", er.eOpposite.name)
ENDIF,
// ordered many to 1 relationship
IF er.ordered = true
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND er.eOpposite.lowerBound = 1
AND er.eOpposite.upperBound = 1
THEN
SET exp.body = append("\\forall o: \\ran(", ozra.name, ") @ ", "\\self = o.", er.eOpposite.name)
ENDIF,
// not ordered many to not ordered many relationship
IF er.ordered = false
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND NOT (er.eOpposite.lowerBound = 1 AND er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = false
THEN
SET exp.body = append("\\forall o: ", ozra.name, " @ ", "\\self \\in o.", er.eOpposite.name)
ENDIF,
// ordered many to ordered many relationship
IF er.ordered = true
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND NOT (er.eOpposite.lowerBound = 1 AND er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = true
THEN
SET exp.body = append("\\forall o: \\ran(", ozra.name, ") @ ", "\\self \\in \\ran(o.", er.eOpposite.name, ")")
ENDIF,
// ordered many to not ordered many relationship
IF er.ordered = true
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND NOT (er.eOpposite.lowerBound = 1 AND er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = false
THEN
SET exp.body = append("\\forall o: \\ran(", ozra.name, ") @ ", "\\self \\in o.", er.eOpposite.name)
ENDIF,
// not ordered many to ordered many relationship
IF er.ordered = false
AND NOT (er.lowerBound = 1 AND er.upperBound = 1) AND NOT (er.eOpposite.lowerBound = 1 AND er.eOpposite.upperBound = 1)
AND er.eOpposite.ordered = true
THEN
SET exp.body = append("\\forall o:", ozra.name, " @ ", "\\self \\in \\ran(o.", er.eOpposite.name, ")")
ENDIF,
pre.specification = exp, ozra.constraint = pre
ENDIF
LINKING EReferenceOZRelAttribute
WITH ozrel = ozra, eref = er, ozclass = ozc, eclass = ec
;
// Pattern to check the existence of Ecore annotation
//
// PATTERN isEAnnotation(ean)
// FORALL EAnnotation ean;
// an example rule converting ecore class annotations to OZ class comment
// RULE EClassEAnnotation2OZClassInvariant(ean, ozp, oze, ec, ozc)
// FORALL EAnnotation ean, EClass ec
// WHERE ean.eModelElement = ec
// AND ec.eAnnotations = ean
// AND lookupClass(ozc, ec)
// MAKE OZComment ozc
// SET ozc.body = ean.source
// ozc.comment = ozc
// ;