Partitioning of Models with Faktor-IPS

Cross-Line Premium Computation Using the Derived Union Association

Since we can now access all coverages in the cross-line class Contract, we can also implement parts of the premium computation in a cross-line manner. The annual base premium of the Contract always equals the sum of the premiums of its coverages. The calculation of the premium for the individual Coverage is then, of course, again line- and coverage-specific.

Adding a Concrete and an Abstract Method to Coverage

In order to be able to call the premium computation of coverages from within the cross-line model, we first make sure that the derived attribute (derived by explicit method call) annualBasePremium of type Money is correctly configured in the class Coverage, and then add two new methods. To do so, we go to the Behaviour tab in the policy component type editor of Coverage and click New in the Methods section. We configure the first method ("computeAnnualBasePremium") with a void return type in the dialog as follows:

methode1 deckung en
Figure 1. Adding a Concrete Method to Coverage

The second method is marked as abstract and uses the return type Money.

methode2 deckung en
Figure 2. Adding an Abstract Method to Coverage

Faktor-IPS generates the following abstract method in the Coverage class:

public abstract Money computeAnnualBasePremiumInternal();

We call this method in our implementation of computeAnnualBasePremium and set the code to @generated NOT.

/**
 * @since 1.0
 *
 * @generated NOT
 */
@IpsGenerated
public void computeAnnualBasePremium() {
	annualBasePremium = computeAnnualBasePremiumInternal();
}

Implementing the Computation Method in Contract

We can now implement the calculation of the annual base premium in the class Contract. Analogously, we add a non-abstract method computeAnnualBasePremium there. In the generated Java code we replace the empty implementation with the following logic.

To prevent the Faktor-IPS code generator from overwriting our implementation during a build, we add NOT to the @generated annotation:
/**
* @since 1.0
* @generated NOT
*/
public void computeAnnualBasePremium() {
    getCoverages().forEach(Coverage::computeAnnualBasePremium);
    annualBasePremium = getCoverages().stream()
            .map(Coverage::getAnnualBasePremium)
            .collect(Money.sum())
            .orElse(Money.NULL);
}

Overriding the Method in HomeBaseCoverage

In the line-specific coverage classes we add the method via the IPS editor as well. To do so, we go to the Behaviour tab and click Override to select the method defined in the superclass. We then implement the concrete logic in the Java editor. For HomeBaseCoverage the implementation looks like this, for example:

/**
 * @since 1.0
 *
 * @generated NOT
 */
@Override
@IpsGenerated
public Money computeAnnualBasePremiumInternal() {
	var rateTable = getRateTable();
	if (rateTable != null) {
		var row = rateTable.findRowNullRowReturnedForEmptyResult(homeContract.getRatingDistrict());
		return homeContract.getSumInsured()
		        .divide(1000, RoundingMode.HALF_UP)
				.multiply(row.getPremiumRate(), RoundingMode.HALF_UP);
	}
	return Money.NULL;
}

Here too, @generated must be extended with NOT so that the code generator does not regenerate the method.