Building bridges also comprises four activities:
Specifying Mapping Functions
At this stage, on the one hand, we have a source model, and on the other, a target model that captures the abstractions that implement the concepts of the source model. The target model contains and formalizes knowledge about the target platform's structure and behavior. The problem now is to link these models together. We do this by specifying mapping functions, which we discussed in Chapter 5.
Once it's clear what the mapping is supposed to do, a mapping function implementor is faced with the following questions: How can a mapping function be specified such that it's easily extensible? What kind of notation should be used to express the mapping function specification? Can the concepts of MDA be applied to the specification of mapping functions by capturing the specifications in models and then using mapping functions to transform these models into executable implementations?
Interwoven with these issues about implementation techniques are questions regarding the particular details of the mapping output, such as, What are optimization criteria for target models, such as readability, style, aesthetics, efficiency, straightforward and recognizable mapping of source model concepts, and so forth?
As we pointed out in Chapter 5, the jury is still out as to which approach is best suited for expressing a mapping function.
Marking the Models
How did we know that an arbitrary source model entity should be persistent? In some cases, it may be possible to work this out analytically, but in the general case, we have to tell the system that this one is persistent but that one isn't. Hence, as we discussed in Chapter 6, we mark each model element in the source model to indicate that a particular mapping function must be used to determine the kind of associated target element we desire.
Assume that you have a source model (conforming to some metamodel, of course) and that you have selected a target model. In addition, you have a set of partial mapping functions, with their respective source and target marking models. We assume that these are partial, because if they were complete, the marking models would already be established, and there would be nothing to do. However, the mapping functions and marking models may be so incomplete as to be nonexistent, though as off-the-shelf models become more widespread, this will be less and less likely.
The task at hand is to ensure that an arbitrary conforming source model will map correctly into the selected target model. You may begin with any of the three inputs: a source metamodel, a target metamodel, or a set of mapping rules. We shall assume initially that you're going to start with the source metamodel.
In this case, the first part of the goal is simple: There must be at least one mapping rule for each model element. Note that the rule is from elements in the source metamodel to elements in the target model. This is because we don't care that you exercise every element type in the target metamodel, only that you can produce a correct target model for every possible conforming source model.
In limited circumstances, it's possible for the mapping from the source metamodel to have an incomplete mapping. For example, if your source model (not metamodel!) never makes use of delayed signals, there's no need to ensure there is a mapping for them. (Of course, if you choose this path, then continued vigilance will be required to ensure that no one ever uses delayed signals in the source model. See also Constraint Propagation and Verification in Chapter 11.)
The second part of the goal is to ensure that the mapping rule can be unambiguously selected. Mapping functions will often refer to input marking models that define marks to resolve ambiguities between mapping rules. If the choice of mapping rule is ambiguous, then you must add a discriminating mark to the marking model, and make the appropriate choice for each such ambiguity in the source model, which you'll do by adding marks in each case.
Once every element of the source metamodel has a mapping function, and every element of the source model has a mark or a default rule that unambiguously selects the mapping function, you have established your marking models completely.
Verifying the Mappings
After knowledge has been formalized in a model, and the model has been marked for its defined mapping functions, we must ensure that the combination of models and marks forms valid input for the mapping and that the mapping will produce valid results.
Consider a mapping that generates source code from a UML model. In the UML, it's perfectly fine to specify more than one generalization for one class, where those generalizations are also classes. The specification of more than one class as the generalization of another class can easily be mapped to the source code in C++. However, one can't use the same model to generate Java source code simply by putting the names of the generalizations into the "extends" clause of the class declaration, because Java allows only for single implementation inheritance. This source code would result in a compile error (better, of course, would be for the mapping function to take care of it).
This example demonstrates that the mapping function has to account for some source model constructs that cannot be translated plainly into target model constructs. You must make sure that there's a chain of mappings leading from the most abstract to the least abstract implementation-oriented metamodels. This is the only way to achieve a contiguous path along the mapping chain. Otherwise, knowledge formalized in one platform would be left untransformed on the way to the implementation, and this is undesirable for obvious reasons.
Once each element in the application model has a defined mapping function, execution of the mapping yields a PSM of the target system, as described below.
Transforming the Models
Transforming the models, like program compilation, is anticlimactic. Now that the models are marked, and we know that the mapping function specifications are complete, we can transform the formalized, marked, and verified knowledge into other models or source code comprising the system's implementation.
Note that model verification should occur every time before a mapping gets executed. This will help the team find and avoid errors as early as possible in the MDA process instead of deferring them to a later point.