The Family Model describes the solution family in terms of software architectural elements. Figure 5.5, “Basic structure of Family Models” shows the basic structure of Family Models as a UML class diagram. Both models are derived from the SolutionComponentModel class. The main difference between the two models is that Family Models contain variable elements guarded by restriction expressions. Since Concrete Component Models are derived from Family Models and represent configured variants with resolved variabilities there are no restrictions used in Concrete Component Models. Please note, that older designations of Family Models are Family Component Model or even just Component Model. Following just Family Model will be used to designate those models with restrictions and thus unresolved variability.
The components of a family are organized into a hierarchy that can be of any depth. A component (with its parts and source elements) is only included in a result configuration when its parent is included and any restrictions associated with it are fulfilled. For top-level components only their restrictions are relevant.
A component is a named entity. Each component is hierarchically decomposed into further components or into part elements that in turn are built fromsource elements .
Parts are named and typed entities. Each part belongs to exactly one component and consists of any number of source elements .
A part can be an element of a programming language, such as a class or an object, but it can also be any other key element of the internal or external structure of a component, for example an interface description. pure::variants provides a number of predefined part types, such as ps:class, ps:object, ps:flag, ps:classalias, and ps:variable. The Family Model is open for extension, and so new part types may be introduced, depending on the needs of the users.
Since parts are logical elements, they need a corresponding physical representation or representations. Source elements realise this physical representation. A source element is an unnamed but typed element. The type of a source element is used to determine how the source code for the specified element is generated. Different types of source elements are supported, such as ps:file that simply copies a file from one place to a specified destination. Some source elements are more sophisticated, for example, ps:classaliasfile, which allows different classes with different (aliases) to be used at the same place in the class hierarchy.
The actual interpretation of source elements is the responsibility of the pure::variants transformation engine. To allow the introduction of custom source elements and generator rules, pure::variants is able to host plug-ins for different transformation modules that interpret the generated Variant Result Model and produce a physical system representation from it.
The semantics of source element definitions are project, programming language, and/or transformation-specific.
An example Family Model is shown below:
This model exhibits a hierarchical component structure. System is the top-level component,Memory its only sub component. Inside this component are two parts, a class, and a flag. The class is realized by two source elements. Selecting an element of the family model will show its properties in the Properties view.
A key capability that makes the Family Modelling language more powerful than other component description languages is its support of flexible rules for the inclusion of components, parts, and source elements. This is achieved by placing restrictions on each of these elements.
By default every element is included in a variant if its parent element is included, or if it has no parent element. Restrictions specify conditions under which a configuration element may be excluded from a configuration.
It is possible to put restrictions on any element, and on element properties and relations. An arbitrary number of restrictions are allowed. Restrictions are evaluated in the order in which they are listed. If a restriction rule evaluates to true , the restricted element will be included. That is, a set of restrictions is evaluated as a disjunction of these restriction.
A restriction rule may contain arbitrary (pvSCL) statements. The
most useful rule is
<feature name/id)
which evaluates to
true
if
the feature selection contains the named feature.
Bar
The element/attribute may be included only if the current feature
selection
contains the feature with identifier
Bar
.
Rule 1
not(BarFoos)
Rule2
FoosBar
This is a logical or of two statements. The element will be
included if either
feature
BarFoos
is not in the feature selection or
FoosBar
is in it.
It is also possible to merge both rules into one by using the
or
keyword.
Rule 1 or Rule 2
not(BarFoos) or FoosBar
As for features, each element (component, part, and source element) may have relations to other elements. The supported relations are described in Section 9.2, “Element Relation Types” .
When a configuration is checked, the configuration may be regarded as invalid if any relations are not satisfied.
In the example below, the Cosine class element is given an additionalps:requestsProvider relation to require that a cosine implementation must be present for a configuration to be valid.ps:exclusiveProvider relation statements are used in two different cosine implementations. Either of which could be used in some feature configurations (featureFixedTime and feature Equidistant ). But it cannot be both implementations in the resulting system.
ps:class("Cosine") Restriction: Cosine Relation: ps:requestsProvider = 'Cosine' ps:file(dir = src, file = cosine_1.cc, type = impl): Restriction: FixedTime Relation: ps:exclusiveProvider = 'Cosine' ps:file(dir = src, file = cosine_2.cc, type = impl): Restriction: FixedTime and Equidistant Relation: ps:exclusiveProvider = 'Cosine'
In the example given above an error message would be generated if
the restrictions
for both elements were valid, as it would not be known which element
to include. Below,
this example is extended by using the
ps:defaultProvider/ps:expansionProvider
relations to define a
priority for deciding which of the two conflicting elements should be
included. These
additional relation statements are used to mark the two cosine
implementations as an
expansion point. The source element entry forcosine_1.cc
specifies that this element should only be included if no
more-specific element can be included (ps:defaultProvider
). In this
example,cosine_2.cc
will be included when feature
FixedTime
and feature
Equidistant
are both
selected, otherwise the default implementation,cosine_1.cc
is included. If the Auto Resolver for selection problems is
activated then the appropriate implementation will be included
automatically, otherwise
an error message will highlight the problem.
ps:class("Cosine") Restriction: Cosine Relation: ps:requestsProvider = 'Cosine' ps:file(dir = src, file = cosine_1.cc, type = impl): Restriction: FixedTime Relation: ps:exclusiveProvider = 'Cosine' Relation: ps:defaultProvider = 'Cosine' Relation: ps:expansionProvider = 'Cosine' ps:file(dir = src, file = cosine_2.cc, type = impl): Restriction: FixedTime and Equidistant Relation: ps:exclusiveProvider = 'Cosine' Relation: ps:expansionProvider = 'Cosine'