This section describes the transformation definition for transforming PIMs in UML to models of EJB components. The definition is identical to the rules used in section 5.2. As explained before, we need the metamodel for both the source and the target language. The source language is UML, for which we already introduced a metamodel in Figure 10-1. The target language is the coarse grained EJB model described in section 5.2.1. The metamodel for the coarse grained EJB components used is depicted in Figure 10-3. For the sake of simplicity, the transformations and metamodel elements for enumerations and data types without operations (that is, structs) are not defined. These are used for the Style and Address classes in Rosa's model.
-
There is a transformation from each UML class to a key class in the EJB model. For each class in the UML model, a separate key class is generated. This is needed in the EJB platform. This rule formalizes rule 1 in section 5.2.2.
Transformation ClassToKeyClass (UML, EJB) { source class : UML::Class; target keyClass : EJB::EJBKeyClass; id : EJB::EJBAttribute; target condition id.class = keyClass and id.type = Integer; unidirectional; mapping class.name + 'Key' <~> keyClass.name; class.name + 'ID' <~> id.name; }
-
This is a transformation from each UML association class to a key class in the EJB model with two attributes that identify the associated class. Note that this rule only supports association classes between ordinary (non association) classes.
Transformation AssociationClassToKeyClass (UML, EJB) { source associationClass : UML::AssociationClass target keyClass : EJB::EJBKeyClass; id1 : EJB::EJBAttribute; id2 : EJB::EJBAttribute; target condition id1.class = keyClass and id1.type = Integer and id2.class = keyClass and id2.type = Integer; unidirectional; mapping associationClass.name <~> keyClass.name; associationClass.end->first().type.name + 'ID' <~> id1.name; associationClass.end-> first().otherEnd.type.name.concat('ID') <~> id2.name; }
-
Each class that is not the part of a composite aggregation is mapped to an EJB entity component. Classes that are composite parts of other classes do not conform to this rule and are transformed by the next rule. This rule formalizes rule 2 in section 5.2.2.
Transformation ClassToEntityComponent (UML, EJB) { source class : UML::Class; target entityComponent : EJB::EJBEntityComponent; rootDataClass : EJB::EJBDataClass; dataSchema : EJB::EJBDataSchema; servingAttribute : EJB::EJBServingAttribute; source condition not class.associationEnds()->exists( otherEnd.composition = true); target condition servingAttribute.class = entityComponent and servingAttribute.type = rootDataClass and rootDataClass.package = dataSchema unidirectional ; mapping class.name <~> entityComponent.name; class.name <~> rootDataClass.name; class.name <~> servingAttribute.name; class.name <~> dataSchema.name; class.getAllContained(Set(UML::Class){}).operations() <~> entityComponent.feature; class.feature->select(oclKindOf(UML::Attribute) or oclKindOf(UML::AssociationEnd)) <~> rootDataClass.feature; class.getAllContained(Set(UML::Class){}) <~> entityComponent.usedTable; }
-
The following transformation defines the mapping from a UML class to an EJB data class. The source condition states that this transformation can only be applied when the UML class is part of a composite aggregation. This rule formalizes a part of rule 3 in section 5.2.2.
Transformation ClassToDataClass (UML, EJB) { source class : UML::Class; target nonRootClass : EJB::EJBDataClass; source condition class.associationEnds()->exists(otherEnd.composition = true); unidirectional; mapping class.name <~> nonRootClass.name; class.feature->select(oclKindOf(UML::Attribute) or oclKindOf(UML::AssociationEnd)) <~> rootDataClass.feature; class.getOuterMostContainer() <-> nonRootClass.package; }
-
Each association is transformed into an EJB association. This rule formalizes rule 4 in section 5.2.2.
Transformation AssociationToDataAssociation (UML, EJB) { source assoc : UML::Association; target dataAssoc : EJB::EJBDataAssociation; source condition assoc.end->exists(composition); unidirectional ; mapping assoc.name <~> dataAssoc.name; assoc.end <~> dataAssoc.end; assoc.getOuterMostContainer() <~> dataAssoc.package; }
-
This rule formalizes a part of rule 5 in section 5.2.2.
Transformation AssociationClassToDataClass (UML, EJB) { source associationClass : UML::AssociationClass; target nonRootClass : EJB::EJBDataClass; source condition class.feature->exists(end : AssociationEnd end.otherEnd.composition); unidirectional; mapping associationClass.name <~> nonRootClass.name; associationClass.feature->select(oclKindOf(UML::Attribute) or oclKindOf(UML::AssociationEnd)) <~> rootDataClass.feature; associationClass.getOuterMostContainer() <~> nonRootClass.package; }
-
The following rule formalizes rule 6 in section 5.2.2. This is a straightforward transformation from UML attribute to EJB attribute.
Transformation UMLAttributeToEJBAttribute (UML, EJB) { source umlAttribute : UML::Attribute; target ejbAttribute : EJB::EJBAttribute; unidirectional; mapping umlAttribute.name <~> ejbAttribute.name; umlAttribute.type <~> ejbAttribute.type; }
-
This rule defines a transformation from a UML association end to an EJB association end. The condition of this rule states that it is only applicable if the transformed association end is not crossing an EJB data schema. In this case, the type of the EJB association end is an EJB data class. This rule formalizes a part of rule 4 in section 5.2.2.
Transformation UMLAssociationEndToEJBAssociationEnd(UML, EJB) { source umlAssociationEnd : UML::AssociationEnd; target ejbAssociationEnd : EJB::EJBAssociationEnd; source condition umlAssociationEnd.association.oclIsTypeOf(Association) and umlAssociationEnd.class.getOuterMostContainer() = umlAssociationEnd.type.getOuterMostContainer(); unidirectional; mapping umlAssociationEnd.name <~> ejbAssociationEnd.name; umlAssociationEnd.upper <~> ejbAssociationEnd.upper; umlAssociationEnd.lower <~> ejbAssociationEnd.lower; umlAssociationEnd.composition <~> ejbAssociationEnd.composition; umlAssociationEnd.type <~> ejbAssociationEnd.type.oclAsType(EJB::EJBDataClass); }
-
This rule also defines a transformation from a UML association end to an EJB association end. The condition of this rule states that it is only applicable if the transformed association end is crossing an EJB data schema. In this case, the type of the EJB association end is an EJB key class. This rule formalizes a part of rule 4 in section 5.2.2.
Transformation UMLAssociationEndToEJBAssociationEnd(UML, EJB) { source umlAssociationEnd : UML::AssociationEnd; target ejbAssociationEnd : EJB::EJBAssociationEnd; source condition umlAssociationEnd.association.oclIsTypeOf(Association) and not umlAssociationEnd.class.getOuterMostContainer() = umlAssociationEnd.type.getOuterMostContainer(); unidirectional; mapping umlAssociationEnd.name <~> ejbAssociationEnd.name; umlAssociationEnd.upper <~> ejbAssociationEnd.upper; umlAssociationEnd.lower <~> ejbAssociationEnd.lower; umlAssociationEnd.composition <~> ejbAssociationEnd.composition; umlAssociationEnd.type <~> ejbAssociationEnd.type.oclAsType(EJB::EJBKeyClass); }
-
The following rule transforms association ends from an association class into associations in the EJB data schemes. This is because we need two associations per association class to implement them in the EJB model that does not support association classes in the metamodel. This rule formalizes a part of rule 5 in section 5.2.2.
Transformation UMLAssociationClassEndToEJBAssociation(UML, EJB) { source umlAssociationEnd : UML::AssociationEnd; target ejbAssociation : EJB::EJBAssociation; ejbAssociationEnd1 : EJB::EJBAssociationEnd; ejbAssociationEnd2 : EJB::EJBAssociationEnd; source condition umlAssociationEnd.upper <> 1 and umlAssociationEnd.association.oclIsTypeOf(AssociationClass) and umlAssociationEnd.association.getOuterMostContainer() = umlAssociationEnd.type.getOuterMostContainer(); target condition ejbAssociationEnd1.lower = 0 and ejbAssociationEnd1.upper = * and ejbAssociationEnd2.lower = 1 and ejbAssociationEnd2.upper = 1 and ejbAssociationEnd1.composition = false and ejbAssociationEnd1.association = ejbAssociation and ejbAssociationEnd2.association = ejbAssociation; unidirectional; mapping umlAssociationEnd.type.name <~> ejbAssociationEnd2.name; umlAssociationEnd.composition <~> ejbAssociationEnd2.composition; umlAssociationEnd.type <~> ejbAssociationEnd2.type.oclAsType(EJB::EJBDataClass); umlAssociationEnd.type <~> ejbAssociationEnd1.class.oclAsType(EJB::EJBDataClass); umlAssociationEnd.association.name <~>ejbAssociationEnd1.name; umlAssociationEnd.association <~> ejbAssociationEnd1.type.oclAsType(EJB::EJBDataClass); umlAssociationEnd.association <~> ejbAssociationEnd2.class.oclAsType(EJB::EJBDataClass); }
-
If we cross different EJB data schemes, we only need an association end pointing out of the EJB data schema to an EJB key class. This rule formalizes a part of rule 5 in section 5.2.2.
Transformation UMLAssociationClassEndToEJBAssociation(UML, EJB) { source umlAssociationEnd : UML::AssociationEnd; target ejbAssociationEnd2 : EJB::EJBAssociationEnd; source condition umlAssociationEnd.upper <> 1 and umlAssociationEnd.association. oclIsTypeOf(UML::AssociationClass) and not umlAssociationEnd.association.getOuterMostContainer() = umlAssociationEnd.type.getOuterMostContainer(); target condition ejbAssociationEnd2.lower = 1 and ejbAssociationEnd2.upper = 1; unidirectional; mapping umlAssociationEnd.type.name <~> ejbAssociationEnd2.name; umlAssociationEnd.composition <~> ejbAssociationEnd2.composition; umlAssociationEnd.type <~> ejbAssociationEnd2.type.oclAsType(EJB::EJBKeyClass); umlAssociationEnd.association <~> ejbAssociationEnd2.class.oclAsType(EJB::EJBDataClass); }
-
An Operation in UML becomes a business method in the EJB model. This rule formalizes a part of rule 7 in section 5.2.2.
Transformation UMLOperationToBusinessMethod(UML, EJB) { source umlOperation : UML::Operation; target businessMethod : EJB::BusinessMethod; unidirectional; mapping umlOperation.name <~> businessMethod.name; umlOperation.parameter <~> businessMethod.parameter; }
-
UML Parameters are transformed into EJB Parameters.
Transformation UMLParameterToEJBParameter(UML, EJB) { source umlParameter : UML::Parameter; target ejbParameter : EJB::EJBParameter; unidirectional; mapping umlParameter.name <~> ejbParameter.name; umlParameter.type <~> ejbParameter.type; }
At the lowest level we need to transform UML datatypes to EJB datatypes. This transformation is not defined here, but there should be a number of (predefined) transformations at the lowest level of UML to EJB datatypes. The definition below simply states that there must be such a transformation from UML to EJB datatypes.
The following query operations are defined on the UML metamodel, and used in the transformations above. The definition uses the OCL 2.0 functionality to define additional operations on existing classes in a model.
-
The operation getAllContained() returns a set of all classes that are directly or indirectly composed via a composite association, including the class itself.
context Class def: getAllContained( contained : Set(Class) ) : Set(Class) = if contained->includes(self) then result = contained else let allContained = contained->including(self) in result = self.feature-> select(end : AssociationEnd end.composition)-> collect(type)-> iterate( containedClass : Class ; acc : Set(Class) = allContained acc->union(containedClass.getAllContained(allContained)) endif
-
The operation getOuterMostContainer returns the outermost class that incorporates this class through a composition association.
context Class def : getOuterMostContainer() : Class = if self.feature->exists(end : AssociationEnd end.otherEnd.composition) then result = self.feature->select(end : AssociationEnd end.otherEnd.composition)->first().type.getOuterMostContainer() else result = class endif
-
The operation getOuterMostContainer returns the outermost class that incorporates this association through a composition association.
context Association def: getOuterMostContainer() : Class = result = self.end->select(end : AssociationEnd end.otherEnd.composition) ->first().type.getOuterMostContainer()
-
The operation getOuterMostContainer returns the outermost class that incorporates this association class through a composition association.
context AssociationClass def : getOuterMostContainer() : Class = if self.end->size() = 1 -- is one way navigable then result = self.end->first().class.getOuterMostContainer() else result = self endif