Skip to main content

Expanders using Data Resources

· 3 min read
Koen De Cock
Koen De Cock
R&D Engineer

DataResources have become a useful tool for expansion-resources to provide information to the Expanders. This post aims to describe how we can use the information provided by the data-resources in a set of Expanders, to gain insight in how the Expanders work. It gives a number of examples of Expanders using DataResources to make a list of libraries, option types and validation rules.

The data from DataResources is stored in a DataRegistryComposite. This object is available in mapping file as dataRegistry. The examples here will all work around the getComposites(String) method, which returns a list of all instances of an ElementType.

Expander 1. Listing libraries

Library elements define runtime libraries used by the expanded projects. The logic deciding which libraries are added to the pom.xml files depends on the LayerImplementations of each LayerTypes. This example omits that complexity and instead filters on Technologies.

<?xml version="1.0" encoding="UTF-8" ?>
<mapping xmlns="https://schemas.normalizedsystems.org/xsd/expanders/2023/1/0/mapping">
<list name="libraries" eval="dataRegistry.getComposites('net.democritus.settings.Library')"
param="lib">
<filter name="onlyApplicableLibraries" eval="technologies.has(lib.technology.name)"/>
<value name="name" eval="lib.name"/>
<value name="groupId" eval="lib.groupId"/>
<value name="artifactId" eval="lib.artifactId"/>
<value name="version" eval="lib.version"/>
<value name="technology" eval="lib.technology.name"/>
<value name="provider" eval="lib.getMetadata('origin.expansionResource').orElse('-')"/>
</list>
</mapping>
ExpansionResource metadata

Most DataResource elements contain metadata about the location where the data was found. To use, the most interesting information is the expansion-resource that declares this DataResource. This can be found by calling composite.getMetadata('origin.expansionResource'), which returns Optional<String>.

Expander 2. Listing deprecated option types

Most up-to-date expansion-resources declare the options they support as OptionTypes.

We can filter on OptionTypes with a deprecation warning or an expiration time. The example separates the options that have yet to be expired and the ones that have already expired.

<?xml version="1.0" encoding="UTF-8" ?>
<mapping xmlns="https://schemas.normalizedsystems.org/xsd/expanders/2023/0/0/mapping">
<let name="expirationHelper" eval="new org.normalizedsystems.example.OptionTypeExpirationHelper()"/>
<list name="deprecatedOptionTypes" eval="dataRegistry.getComposites('net.democritus.elements.OptionType')"
param="opt">
<filter name="deprecatedOptions" eval="not opt.deprecationWarning.empty or not opt.validUntil.empty"/>
<filter name="isNotExpired" eval="not expirationHelper.isExpired(opt)"/>
<value name="name" eval="opt.name"/>
<value name="validUntil" eval="opt.validUntil"/>
<value name="description" eval="opt.description.replace('\n', ' ')"/>
<value name="reason" eval="opt.deprecationWarning"/>
<value name="provider" eval="opt.getMetadata('origin.expansionResource').orElse('-')"/>
</list>
<list name="expiredOptionTypes" eval="dataRegistry.getComposites('net.democritus.elements.OptionType')"
param="opt">
<filter name="hasExpirationTime" eval="not opt.validUntil.empty"/>
<filter name="isExpired" eval="expirationHelper.isExpired(opt)"/>
<value name="name" eval="opt.name"/>
<value name="validUntil" eval="opt.validUntil"/>
<value name="description" eval="opt.description.replace('\n', ' ')"/>
<value name="reason" eval="opt.deprecationWarning"/>
<value name="provider" eval="opt.getMetadata('origin.expansionResource').orElse('-')"/>
</list>
</mapping>

Expander 3. Listing option types

We can also get a lot more information from the OptionType elements.

<?xml version="1.0" encoding="UTF-8" ?>
<mapping xmlns="https://schemas.normalizedsystems.org/xsd/expanders/2023/0/0/mapping">
<list name="optionTypes" eval="dataRegistry.getComposites('net.democritus.elements.OptionType')"
param="opt">
<filter name="notDeprecated" eval="opt.deprecationWarning.empty and opt.validUntil.empty"/>

<value name="name" eval="opt.name"/>
<value name="docLink" eval="opt.documentationLink"/>
<value name="hasDocLink" eval="not opt.documentationLink.empty"/>
<value name="alias" eval="opt.alias.replaceAll('\\s*,\\s*', ', ')"/>
<value name="hasAlias" eval="not opt.alias.empty"/>

<value name="description" eval="opt.description.replace('\n', ' ')"/>

<list name="properties" eval="{'alwaysEnabled', 'redundant', 'hidden', 'cascading'}" param="prop">
<filter name="isEnabled" eval="opt[prop]"/>
<value name="name" eval="prop"/>
</list>

<value name="provider" eval="opt.getMetadata('origin.expansionResource').orElse('-')"/>

<value name="defaultValue" eval="opt.defaultValue"/>
<value name="hasDefaultValue" eval="not opt.defaultValue.empty"/>
<group name="value" if="opt.valueConstraint neq null">
<value name="isRequired" eval="opt.valueConstraint.isRequired"/>
<value name="noValue" eval="opt.valueConstraint.noValue"/>
<value name="regex" eval="opt.valueConstraint.matchRegularExpression.replace('|', '&amp;#124;')"/>
<value name="hasRegex" eval="not opt.valueConstraint.matchRegularExpression.empty"/>
</group>

<list name="elementTypes" eval="opt.elementTypes" param="elementType">
<value name="name" eval="elementType.name"/>
</list>
</list>
</mapping>

Expander 4. Listing validation rules

ValidationRules (as well as Transmuters) are a bit special. We create ValidationRules by implementing classes and annotating them with @ValidationRule. However, behind the scenes an annotation-processor creates a DataResource files describing these ValidationRules.

And thus, the ValidationRules are also available as data in the DataRegistry.

To make everything run smoothly, it's best to add some dependencies on the validation metamodel:

<dependencies>
<dependency>
<groupId>net.democritus.validations.model</groupId>
<artifactId>validations-core</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>net.democritus.validations.model</groupId>
<artifactId>validations-test-support</artifactId>
<version>3.3.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8" ?>
<mapping xmlns="https://schemas.normalizedsystems.org/xsd/expanders/2023/0/0/mapping">
<list name="groups" eval="dataRegistry.getComposites('net.democritus.validations.ValidationGroup')"
param="group">
<value name="name" eval="group.name"/>
<value name="provider" eval="group.getMetadata('origin.expansionResource').orElse(null)"/>
<list name="rules" eval="group.rules" param="rule">
<value name="name" eval="rule.name"/>
<value name="element" eval="rule.element"/>
<value name="severity" eval="rule.severity.name"/>
<value name="description" eval="rule.description.replace('\n', ' ')"/>
</list>
</list>
</mapping>