##### Feature references

[[feature-refs]]There are cases when a value range of a parameter of one feature spec is defined by a set of existing in the configuration model values of an ID parameter from another feature spec. In other words, a feature spec may declare certain parameters as references to other feature ID parameters. (In a relational database, this would be a foreign key reference).

In a feature spec a simple feature reference would look like

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP"/>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p"/>
   </params>
 </feature-spec>
----

Attribute *feature* in the *ref* element contains a name of the referenced feature-spec. Note that we have not provided which parameter of *featureC* references the ID parameter of *featureP*. This example also demonstrates the *implicit reference parameter mapping*.

IMPORTANT: The implicit reference parameter mapping rule is based on the expectation that the feature spec declaring a reference includes parameters with the names matching the ID parameter names of the referenced feature spec.

So the example above will work if one of the following statements is true:

. *featureP* declares parameter *p* and it is its only feature-id parameter;

. *featureP* declares parameter *name* and it is its only feature-id parameter;

. *featureP* declares parameters *name* and *p* and both of them are its only feature-id parameters.


.The complete set of a feature reference declaration attributes
[options="autowidth"]
|===
|Attribute name |Required |Default |Description

|*dependency* |false |null (current feature-pack) |The feature-pack dependency name the referenced feature spec belongs to.

|*feature* |true |null |The name of the referenced feature spec.

|*name* |false |The value of the *feature* attribute |Unique feature reference name.

|*nillable* |false |false |Whether a reference is nillable or not.

|*include* |false |false |Whether the referenced feature should automatically be included into the config model if it was not explicitly configured.
|===


###### Custom reference parameter mapping

Suppose we want to explicitly map parameters in the reference declaration. The example below will correspond to the statement 1. from the example above.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP">
       <param name="p" maps-to="p"/>
     </ref>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p"/>
   </params>
 </feature-spec>
----

Now let's suppose that *featureP*'s ID parameter is in fact *name* but we still want to use parameter *p* as the reference to *featureP*.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP">
       <param name="p" maps-to="name"/>
     </ref>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p"/>
   </params>
 </feature-spec>
----

If *featureP* had more than one ID parameter, e.g.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureP">
   <params>
     <param name="id1" feature-id="true"/>
     <param name="id2" feature-id="true"/>
   </params>
 </feature-spec>
----

Then the reference parameter mapping in *featureC* could look like:

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP">
       <param name="p1" maps-to="id1"/>
       <param name="p2" maps-to="id2"/>
     </ref>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p1"/>
     <param name="p2"/>
   </params>
 </feature-spec>
----


###### Nillable feature references

Feature reference resolves to null if one of the feature reference parameters is null. If a reference resolves to null and its not marked as nillable in the feature spec, the provisioning will fail with an error. Here is an example of a nillable reference declaration:

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP" nillable="true">
       <param name="p1" maps-to="id1"/>
       <param name="p2" maps-to="id2"/>
     </ref>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p1" nillable="true"/>
     <param name="p2"/>
   </params>
 </feature-spec>
----


###### External feature references

A feature may reference a feature from another feature-pack. The origin of the external feature spec is specified in the *dependency* attribute of the feature reference declaration. The value of the *dependency* attribute must match the value of the *name* element of the feature-pack dependency (the referenced feature spec belongs to) declaration in the feature-pack.xml file.

For example, suppose, feature-pack *fp1* depends on feature-pack *fp2*.

[source,xml]
----
 <feature-pack xmlns="urn:jboss:galleon:feature-pack:1.0"
                groupId="org.jboss.pm.test" artifactId="fp1" version="1.0.0">
    <dependencies>
        <dependency groupId="org.jboss.pm.test" artifactId="fp2" version="2.0.0">
            <name>fp2-dep</name>
        </dependency>
    </dependencies>
 </feature-pack>
----

*fp2* includes a feature spec *featureP*

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureP">
   <params>
     <param name="p" feature-id="true"/>
   </params>
 </feature-spec>
----

And *fp1* includes a feature spec *featureC* which declares a reference to *featureP*

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref dependency="fp2-dep" feature="featureP"/>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p"/>
   </params>
 </feature-spec>
----


###### Implicit feature reference parameter initialization

[[feature-fk-init]]Let's suppose we have a parent-child relationship between two feature specs, e.g.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureP">
   <params>
     <param name="parentId" feature-id="true"/>
   </params>
 </feature-spec>
----

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP"/>
   </refs>
   <params>
     <param name="childId" feature-id="true"/>
     <param name="parentId"/>
   </params>
 </feature-spec>
----

If we were to add features of these specs to a config, it could look like this

[source,xml]
----
 <config>
   <feature spec="featureP">
     <param name="parentId" value="parent1"/>
   </feature>
   <feature spec="featureC">
     <param name="childId" value="child1"/>
     <param name="parentId" value="parent1"/>
   </feature>
 </config>
----

This approach is very verbose, the value for the *parentId* parameter is set on every feature. There is a more compact way of expressing the same configuration using nesting, e.g.

[source,xml]
----
 <config>
   <feature spec="featureP">
     <param name="parentId" value="parent1"/>
     <feature spec="featureC">
       <param name="childId" value="child1"/>
     </feature>
   </feature>
 </config>
----

As can be seen, the *parentId* parameter is initialized only once on the parent feature. The *parentId* of the child feature will be implicitly initialized to the value of the *parentId* of the parent.

IMPORTANT: When a feature is nested, the tool will look in the feature spec of the nested feature for a reference declaration with the name matching the outer feature spec and, if it is found, the tool will resolve the reference parameter mappings and will initialize the parameters of the child feature referencing the parent.

In case the reference name is different from the referenced feature spec name, i.e. it was explicitly set in the reference spec, e.g.
[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref feature="featureP" name="parent"/>
   </refs>
   <params>
     <param name="childId" feature-id="true"/>
     <param name="parentId"/>
   </params>
 </feature-spec>
----

Then the name of the reference has to be explicitly specified when the child feature is nested using the *parent-ref* attribute, e.g.
[source,xml]
----
 <config>
   <feature spec="featureP">
     <param name="parentId" value="parent1"/>
     <feature spec="featureC" parent-ref="parent">
       <param name="childId" value="child1"/>
     </feature>
   </feature>
 </config>
----

NOTE: it is also possible to <<fg-in-features,include a feature-group as a child of the feature>>.

###### Implicit inclusion of referenced features into the configuration

It is possible to configure feature references so that when the resolved referenced feature ID is not found in the configuration model, instead of failing with the referential integrity constraint error, implicitly include the referenced feature into the configuration model initializing it its configured default values. This is done by simply setting the *include* attribute of the feature reference declaration to *true*.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="featureC">
   <refs>
     <ref dependency="fp2-dep" feature="featureP" include="true"/>
   </refs>
   <params>
     <param name="name" feature-id="true"/>
     <param name="p"/>
   </params>
 </feature-spec>
----


###### Multiple references to the same feature spec

Suppose a feature needs to declare more than one reference to the same feature spec. For example let's model a chain having a feature spec called *link*. The *link* must have an ID parameter, let it be called *id*. Then it has to include a parameter to reference to the previous link and another parameter to reference the next link in the chain. The following, although looking right from the parameter mapping perspective, will clearly won't work

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="link">
   <refs>
     <ref feature="link">
       <param name="prev-id" maps-to="id"/>
     </ref>
     <ref feature="link">
       <param name="next-id" maps-to="id"/>
     </ref>
   </refs>
   <params>
     <param name="id" feature-id="true"/>
     <param name="prev-id" nillable="true"/>
     <param name="next-id" nillable="true"/>
   </params>
 </feature-spec>
----

Feature references must have a unique name. In this case, both reference names are set to *link* and the provisioning tool will fail to process this spec. To workaround the error explicit names have to be assigned to the reference declarations, e.g.

[source,xml]
----
 <feature-spec xmlns="urn:jboss:galleon:feature-spec:1.0" name="link">
   <refs>
     <ref name="prev" feature="link">
       <param name="prev-id" maps-to="id"/>
     </ref>
     <ref name="next" feature="link">
       <param name="next-id" maps-to="id"/>
     </ref>
   </refs>
   <params>
     <param name="id" feature-id="true"/>
     <param name="prev-id" nillable="true"/>
     <param name="next-id" nillable="true"/>
   </params>
 </feature-spec>
----


###### Processing of features with references

One of the responsibilities of the provisioning tool is to order the features from the resolve configuration model for processing by the provisioning plugins that generate the final installation configuration files. While the general rule is to preserve the order in which the features where added to the configuration model, when feature A references feature B, feature B will get the priority will be processed by the provisioning plugins before feature A to not break the referential integrity of the generated model (if it is significant for the consuming plugin).


###### Circular feature references

The provisioning mechanism is capable of identifying circular references (circular reference graphs). It does not throw an error if a circular reference graphs is detected. The responsibility of the provisioning mechanism is make sure the configuration model is valid and all the referential integrity constraints are satisfied. From this point of view circular references are not illegal.

The issue with circular references is the ordering of the features when configuration model is processed by the product specific plugins that generate the final configuration files. In some cases the order of the features will not be significant but in some cases it will be. So the rule is 

IMPORTANT: When a circular reference graph is identified, the feature that was added to the configuration model first will be processed by the provisioning plugins first, the rest of the features from the grapth will be processed respecting the references.
