ModelLoadingListeners
ModelLoadingListeners are custom logic that hook into the Model Loading logic.
Listeners can be defined in DataResources, they describe a ModelLoadingStep to which to subscribe and an implementation that point to a java class. After the step in the model loading process has been performed, all listeners subscribed to that step will be executed.
You can subscribe to any of these steps:
- ExtractResourcesStep
- PrepareModelStep
- ReadModelStep
- ConvertModelStep
- EnrichModelStep
- ConfigureExpansionStep
Usage
- modelLoadingListeners.xml
- MyModelLoaderListener.java
Add a DataResource file to your expansion-resource:
<dataResource type="expansionControl::ModelLoadingListener">
<modelLoadingListener name="MyModelLoaderListener">
<modelLoadingStep name="ExtractResourcesStep"/>
<implementation>org.example.MyModelLoaderListener</implementation>
</modelLoadingListener>
</dataResource>
Provide a java class that implements the ModelLoadingStepListener
interface.
The interface is typed with the result class of the step (always named after the step, but replace Step with Result).
import net.democritus.model.common.ModelLoadingContext;
import net.democritus.model.common.ModelLoadingStepListener;
import net.democritus.model.resources.ExtractResourcesResult;
public class MyModelLoaderListener implements ModelLoadingStepListener\<ExtractResourcesResult> {
@Override
public void afterStep(ExtractResourcesResult result, ModelLoadingContext context) {
// Do stuff
}
}
The net.democritus.mapping.CompositeElementFinder
class has a findAll()
method that can be used to find all
instances of a composite in a ExpansionCompositeModel
object, which can otherwise be hard to traverse.
Set<ValueFieldComposite> valueFields = CompositeElementFinder
.findAll(result.getExpansionCompositeModel(), ValueFieldComposite.class);
Order of execution
Some ModelLoadingListeners build on changes made by other listeners. Hence the order of execution is important. By default, the listeners are executed in order of definition. However, this doesn’t cover all use-cases.
ModelLoading listeners can be ordered by defining ModelLoadingGoals. A goal describes what the listeners will attempt to do.
<dataResource type="expansionControl::ModelLoadingGoal">
<modelLoadingGoal name="process-base-options">
<description>Process options that were present in the model from the start.</description>
</modelLoadingGoal>
<modelLoadingGoal name="provide-options">
<description>Provide options based on some logic.</description>
</modelLoadingGoal>
<modelLoadingGoal name="value-type.resolve-prototype">
<description>Resolve prototype inheritance for ValueTypes.</description>
</modelLoadingGoal>
...
</dataResource>
The ModelLoadingListeners can then define which goals they are working on:
<modelLoadingListener name="OptionCascade">
<modelLoadingStep name="ConvertModelStep"/>
<implementation>....OptionCascade</implementation>
<goals>
<goal name="process-base-options"/>
<goal name="provide-options"/>
</goals>
</modelLoadingListener>
If there is a timing restriction for one of the ModelLoadingListeners, they can define a timing:
<modelLoadingListener name="ApplicationInstanceOptionCopier">
<modelLoadingStep name="ConvertModelStep"/>
<implementation>net.democritus.model.options.ApplicationInstanceOptionCopier</implementation>
<goals>
<goal name="provide-options"/>
</goals>
<timings>
<listenerTiming>
<timing name="before"/>
<goal name="process-base-options"/>
</listenerTiming>
</timings>
</modelLoadingListener>
<modelLoadingListener name="AlwaysEnabledOptionPlacer">
<modelLoadingStep name="ConvertModelStep"/>
<implementation>net.democritus.model.options.AlwaysEnabledOptionPlacer</implementation>
<goals>
<goal name="process-base-options"/>
</goals>
<timings>
<listenerTiming>
<timing name="after"/>
<goal name="provide-options"/>
</listenerTiming>
</timings>
</modelLoadingListener>
The listeners will be sorted so that the execution order corresponds to the required timing. In some cases the timing can become impossible and an exception will be thrown. This might occur if there is a cycle. Or when the requested timing is incompatible with the order in which the steps are executed.