-
Notifications
You must be signed in to change notification settings - Fork 35
Description
See parent issue: #1077
When extending a model involved in a translation, whether it is the input of the translation or the output, it is usually required to adjust the translation itself too. Two examples:
- A business participant may extend the input schema XSD with their own specific data, such as a new type of
Product. This product will need to be mapped in a different way. - A business participant may extend the CDM with additional attributes. These attributes will need to be populated by the translation function.
Of course, both types of extension may happen at the same time.
In such a scenario, we want to reuse as much as possible from the original translation, while being able to override the specific parts to handle extensions. Since a translation often consists of multiple functions calling each other, we want to be able to replace the implementation of a single function without having to modify any of its callers. To achieve this, we introduce the concept of a scope.
A scope allows a modeller to override the implementation of certain functions. As an example, suppose we want to implement a new case in above MapProduct function:
namespace cdm.mappings.extended
scope MyScope
import cdm.mappings.*
func ExtendedMapProduct extends MapProduct:
inputs:
product Product (1..1)
output:
result Foo (1..1)
set result:
product switch
BondContract then MapBondContract,
default superThree things are going on here:
- At the top of the file, we define a scope called
MyScope, for which all function overrides in this files will be bound in. - We introduce the
extendskeyword to extend a function and bind the new implementation to the original function within this scope. Note that the inputs and output of the overridden function are required to be equal to the original function. - Within the expression of the function, we call the original function by using the keyword
super(...). This is similar to thesuperkeyword in object oriented languages.
Given such a scope, a modeller can specify that a translation, or any other transformation, is using this scope by using the [scope ...] annotation.
func MapXToY:
[scope MyScope]
...In Java, generated code uses the dependency injection framework Guice to decide which implementation of a function to run. Within this framework, a scope corresponds to a Guice module, in which specific implementations are bound to function interfaces.
Currently, no other code generators implement functions, so this requires no additional generator work aside from Java.