Contents > 9 Extending the Metrics and Rule Engine > 9.1 Metric Procedures > 9.1.2 Implementation of the Metric Procedure
9.1.2 Implementation of the Metric Procedure
The following listing shows the complete implementation of the new metric procedure outlined
in the previous section. Because we heavily utilize the API of the metrics engine,
which already provides much of the functionality, the implementation of the procedure
is quite compact, and essentially contains a nested loop to generate the element pairs.
packacke com.acme;
import java.util.Collection;
import java.util.Comparator;
import com.sdmetrics.math.ExpressionNode;
import com.sdmetrics.metrics.*;
import com.sdmetrics.model.ModelElement;
01 public class MetricProcedurePairwise extends MetricProcedure {
@Override
02 public Object calculate(ModelElement element, Metric metric)
throws SDMetricsException {
03 ProcedureAttributes attributes = metric.getAttributes();
04 Variables vars = new Variables(element);
05 Collection<ModelElement> set =
getRelationOrSet(element, attributes, vars);
06 if (set == null)
07 return Integer.valueOf(0);
08 ExpressionNode pairCondition = attributes.getExpression("paircondition");
09 boolean allTuples = attributes.getBooleanValue("tuples", false);
10 boolean withSelf = attributes.getBooleanValue("withself", allTuples);
11 FilterAttributeProcessor fap = getFilterAttributeProcessor(attributes);
12 SummationHelper sum = new SummationHelper(getMetricsEngine(), attributes);
13 Comparator<ModelElement> comparator = ModelElement.getComparator();
14 for (ModelElement first : fap.validIteration(set, vars)) {
15 vars.setVariable("_first", first);
16 for (ModelElement second : fap.validIteration(set, vars)) {
17 int comp = comparator.compare(first, second);
18 if (comp == 0 && !withSelf)
19 continue;
20 if (comp > 0 && !allTuples)
21 continue;
22 vars.setVariable("_second", second);
23 if (pairCondition == null
|| evalBooleanExpression(element, pairCondition, vars)) {
24 sum.add(second, vars);
}
}
}
25 return sum.getTotal();
}
}
Let's go through the salient points of this implementation line by line:
- 01: All metric procedure classes must have public visibility, a default or no-argument
constructor, and extend the abstract class com.sdmetrics.metrics.MetricProcedure.
- 02: The base class defines the abstract method calculate which we must override.
Input parameters are the model element and the metric to be calculated.
- 03: Class ProcedureAttributes provides access to the attribute values in the
metric definition.
- 04: Class Variables contains the values of variables to be used in metric expressions.
In the constructor, we specify the principal model element for which the metric is calculated.
- 05: Method getRelationOrSet is a helper method provided by the base class to
evaluate the "relation" or "relset" attributes (whichever was specified) as we know them from
metric and set projections.
- 08: Class ExpressionNode represents metric, set, or condition expressions
(see Section 8.5 "Expression Terms"). Here, we obtain the condition expression of the "paircondition" that
we defined.
- 09-10: Here we obtain the values of attributes "tuples" and "withself", providing
default values when the attributes are not set.
- 11: Class FilterAttributeProcessor is a helper class to process the standard filter
attributes ("target", "targetcondition", "element", "eltype", "condition", and "scope").
The method getFilterAttributeProcessor() yields an instance of this class to apply
the filter attributes for the metric at hand.
- 12: Class SummationHelper is a helper class that processes the "sum" and
"stat" attributes.
- 14: We use the filter attribute processor from line 11 to iterate over all elements
specified via the "relation" or "relset" attribute from line 5. The filter attribute processor
automatically discards elements which should be ignored as per the element filter settings
(see Section 4.2.2 "Specifying Filters") for us, applies the filter attributes "target", "element" etc., and
returns an iteration over the resulting elements.
- 15: We define a variable "_first" with the first element of the pair/tuple as value.
- 16-21: In a nested loop, we iterate again over all elements. Depending on the values
of attributes "tuples" and "withself", we skip unwanted pairs/tuples.
- 22: At this point we have identified a relevant pair or tuple, and we define a variable
"_second" with the second element of the pair/tuple as value.
- 23: We evaluate the "paircondition" (if set), making sure to pass the values of the
"_first" and "_second" variables into the evaluation. Method
evalBooleanExpression evaluates condition expressions for model elements and
returns a simple boolean value with the result.
- 24: When the "paircondition" yields true (or was not set), we use the
summation helper from line 12 to either increase the result value by one or process
the "sum" and "stat" attributes if they were specified. Again, we pass the "_first"
and "_second" variables to the summation helper so that the values are available for
the evaluation of the "sum" attribute.
- 25: We return the total as value of the metric.
Prev |
Up |
Next |
Section 9.1.1 "Conception of a New Metric Procedure" | Contents | Section 9.1.3 "Using the New Metric Procedure" |