Recently, some SDMetrics Open Core users approached me with a neat little measurement problem that is ideally suited for this blog. They used Enterprise Architect to create UML 1.3 component diagrams with classifier roles. The XMI output of Enterprise Architect for these diagrams contained several tagged values for the classifier role instances, including two with the tags ‘parent’ and ‘owner’, as in the following XMI excerpt:
<UML:ClassifierRole name="SomeIF" xmi.id="EAID_93FEB324" ...> <UML:ModelElement.taggedValue> <UML:TaggedValue tag="isAbstract" value="false"/> <UML:TaggedValue tag="package" value="EAPK_493C83E5"/> <UML:TaggedValue tag="owner" value="EAID_FC3A16EB"/> ... </UML:ModelElement.taggedValue> </UML:ClassifierRole>
The values of the tags in boldface are actually XMI IDs, referencing other model elements. The challenge was to identify these referenced model elements.
To solve this problem, we had to overcome two hurdles. The first was that SDMetrics did not import the tagged values of classifier roles at all. Out-of-the-box, SDMetrics ignores model elements owned by classifier roles, because the default metrics and rules do not use them. This, however, can be easily fixed. In the XMI transformation file, we just add the “recurse” attribute to the XMI transformation for classifier role (cf. bottom of this section in the user manual):
<xmitransformation modelelement="classifierrole" xmipattern="UML:ClassifierRole" recurse="true"> ... </xmitransformation>
With this modification, SDMetrics also imports all the tagged values of classifier roles.
The second hurdle was that the “value” attribute of the tagged value is a data attribute, not a reference attribute. That means, SDMetrics just stores the value as a plain string, and does not interpret it as a cross-reference to another model element. Using the SDMetrics Open Core API, it is possible to read the string value such as “EAID_FC3A16EB” from the “value” attribute, and search all model elements for the one with that XMI ID. But that would be inefficient and a bit cumbersome.
With a little trick, we can have SDMetrics automatically resolve the cross-reference for us. We extend the meta model element taggedvalue by a new cross-reference attribute, “refvalue”:
<modelelement name="taggedvalue"> <attribute name="tag" type="data">The tag of the tagged value</attribute> <attribute name="value" type="data">The value of the tagged value.</attribute> <attribute name="refvalue" type="ref">The referenced element of the tagged value.</attribute> </modelelement>
Then, for tagged values with tag names ‘owner’ or ‘package’, we store the value in our new attribute refvalue. For all other tagged values, the value goes into the old attribute “value”, as before. We can accomplish this by adding a new conditional XMI transformation to the XMI transformation file as follows:
<xmitransformation modelelement="taggedvalue" xmipattern="UML:TaggedValue" requirexmiid="false" condition="tag='owner' or tag='package'"> <trigger name="tag" type="attrval" attr="tag" /> <trigger name="refvalue" type="attrval" attr="value" /> </xmitransformation>
The condition predicate states to apply this transformation for UML:TaggedValue elements where the value of attribute tag in the XMI file is either ‘owner’ or ‘package’. For these XMI elements, we assign the value of XMI attribute “value” to our new attribute refvalue. Because refvalue is a cross reference attribute, SDMetrics resolves the cross-reference for us during model import. Using the Open Core API, we can simply access the referenced model element with method getRefAttribute(“refvalue”) on the model element that represents the tagged value.
But we can also use this extension to define plain metrics with the SDMetricsML. For example, to count, for a component, the number of classifier roles it “owns” via tagged values:
<metric name="CFRoles" domain="component"> <projection relation="refvalue" targetcondition="tag='owner'" element="context" eltype="classifierrole" /> </metric>
The metric counts all tagged values with tag ‘owner’ whose attribute refvalue points to the component and whose owner is a classifier role.
And there we are, one more measurement problem for SDMetrics that could be solved with a few lines of XML code. The customization features work as advertised.