Modern software development is a complicated process especially when a software system becomes large and complicated. Software developers must apply software refinement in order to proceed from a high-level abstract model to a final executable software system by adding more details over time. Class diagrams are important because they represent the static structure of a software system, and therefore we design a UML profile extending the UML metamodel to support class diagram refinement.
The main idea of this research is to help developers check whether two class diagrams at different levels of abstraction have any semantic inconsistencies that could have been introduced during the refinement process. How to represent the inconsistency between two class diagrams is important in supporting such a model refinement. Here we argue that the refinement rules which can find the inconsistencies between two classes at different levels of abstraction are closely related to the development context. There are no fixed rules; instead the developers can decide which rules are used. To satisfy this flexibility, we propose the UML profile mechanism be applied to represent the consistency rules. The most important advantage of using the UML profile mechanism is that developers can design a profile to reflect their consistency rules depending on their development context. In the following we show how to apply the profile mechanism to define a refinement rule and how our tool, ICER, finds an error.
The UML profile defines some stereotypes that software developers can use to tag classes and relations in the class diagrams at the different levels of refinement. We use OCL constraints to represent refinement rules that elements at the two levels of refinement must adhere to, and use the model instantiation checking feature of our tool to validate a UML model containing the two levels of class diagrams against the UML profile containing these OCL constraints.
The notation we use to separate class diagrams at two different levels within the same UML model is similar to the way we separate specification and instance diagrams within a single UML model. We use packages containing class diagrams at each level and connecting the package containing the higher- level class diagram with the package containing the refined class diagram with a dependency. These packages are located within the instance diagram package. The figure below shows this relation. The package labeled Level 2 is the higher-level class diagram while the package labeled Level 3 is the refined class diagram. As with instance and specification diagram packages, there can be multiple packages within the instance diagram packages as long as there is only one dependency relation between the packages.
In the UML profile for software refinement we define a number of
stereotypes. The stereotype
Refine_Class extending the metaclass
Class is used to tag classes that take part in a refinement relation.
A stereotype that has the prefix
Refined_ represents an element to be
refined, i.e. its instance belongs to a higher-level model. A stereotype with
Refining_ represents an element that is used to refine an
element at the higher-level model.
Refine_Class stereotype we
define a tag named
mapping_name that is used to represent a
refinement relation between two classes during class diagram refinement. If two
classes, one at each level of refinement, have the same value for
mapping_name, then these two classes are involved in some
refinement relation. Each of the other stereotypes have a tag named
refinement_value, which is used to represent elements that are
involved in a refinement relation. All
stereotypes with the same value for
refinement_value are involved
in some refinement relation. In addition to this, each
stereotype also has a tag named
mapping_order, which is an integer
value that represents the order in which the refining element appears in the
relation that is refined in the refined class diagram. The figure below shows
part of the UML profile supporting class diagram refinement.
In the preceding figure two stereotypes,
Refining_Gen, are defined. As an example we will present a
refinement rule involving generalizations, shown in the figure below. The rule
specifies that a generalization between two classes in a higher-level class
diagram can be refined into a series of generalizations involving intermediate
helper classes in the refined class diagram. The bottom part of the figure
The following OCL constraint represents this refinement rule:
context Refined_Gen inv: let matchingGen : Set(Generalization) = Generalization.allInstances()->select(g| g.oclIsKindOf(Refining_Gen) and g.oclAsType(Refining_Gen).refinement_value = self.refinement_value) in self.parent.oclIsKindOf(Refine_Class) and self.child.oclIsKindOf(Refine_Class) and -- no duplicate mapping_order values matchingGen->forAll(a,b | a.oclAsType(Refining_Gen).mapping_order = b.oclAsType(Refining_Gen).mapping_order implies a = b) -- mapping_order values between 1 and size of set of -- Refining_ relations with same refinement_value and matchingGen->forAll(a| a.oclAsType(Refining_Gen).mapping_order >= 1 and a.oclAsType(Refining_Gen).mapping_order <= matchingGen->size()) -- refining end classes match refined end classes -- relation sequence should be numbered from child to parent and matchingGen->exists (a,b | a<>b and a.oclAsType(Refining_Gen).mapping_order = 1 and a.child.oclIsKindOf(Refine_Class) and a.child.oclAsType(Refine_Class).mapping_name = self.child.oclAsType(Refine_Class).mapping_name and b.oclAsType(Refining_Gen).mapping_order = matchingGen->size() and b.parent.oclIsKindOf(Refine_Class) and b.parent.oclAsType(Refine_Class).mapping_name = self.parent.oclAsType(Refine_Class).mapping_name) -- consecutive relations connect the same classes -- relation sequence should be numbered from child to parent and matchingGen->forAll (c,d | (c<>d and c.oclAsType(Refining_Gen).mapping_order + 1 = d.oclAsType(Refining_Gen).mapping_order) implies (c.parent = d.child))
Let us take a look at a UML model using this refinement rule
(download the model, download the
XML file). The figure
below shows the high-level class diagram. Notice that there can be multiple
sets of classes and relations that are tagged with the appropriate stereotypes.
However, each refined relation (association or generalization in this case)
have different values for
refinement_value so there is no
ambiguity as to which refining elements in the refined class diagram correspond
to which refined elements in the higher-level class diagram. The
mapping_name tagged value for each <<Refine_Class>>
class is not shown because they are in documentation tags (see
Notation). For our example, the class A
has the value "src1" while the class C has the value "src3" for
The figure below shows part of the refined class diagram for the generalization
between classes A and C in the diagram before it. The names of
the two end classes have been changed during the refinement process. However,
the values of
refinement_value for X and TheChild
are still "src1" and "src3" respectively. A helper class G1 has been
added in between the original two classes. However, there is an error because
now TheChild is no longer a descendant of X as it was in the
Before proceeding let us first take a look at how to validate software refinement with the tool.
When ICER reads in the UML model containing the UML profile for refinement and the class diagrams at the different levels, the OCL constraint for the generalization tagged with <<Refined_Gen>> in the more abstract class diagram will be checked. Because there is an error in the refined class diagram, the tool will find the error, shown in the diagram below.
From the output of the tool we know that the refinement is not correct. Right now we cannot pinpoint exactly which part in the OCL constraint representing the refinement rule was violated, but if there are multiple refining relations in the UML model we can at least narrow it down to a particular set of refining relations. The error in this example can be fixed by reversing the generaliztion between X and G1:
Now when we export the UML model and rerun ICER on the exported XMI file we get no errors from the resulting execution as shown below.