API

There are two sources of complexity in the design of the fmp plug-in: extensible metamodel and constraint propagation & resolution.

Overview of the API

Metamodel

The metamodel is represented as a feature model as shown on the right side of the figure below. It contains three diagrams, one for each feature model element: Feature, FeatureGroup and Reference. In the example below, feature Catalog selected in the model is an instance of the meta-feature Feature. Properties view shows the configuration of the meta-feature Feature. The properties of model elements can be extended by extending the meta-feature, such as Priority extension.

Properties view on the right shows the configuration of the meta-meta-feature Feature from the meta-metamodel. The meta-metamodel is hardcoded and cannot be extended. Note, that the metamodel is not a complete one - it does not contain structural dependencies between model elements such as 'a feature group can contain features and references, but not other feature groups'.

The implementation of the plug-in is based on Eclipse Modeling Framework (EMF). The next figure shows a complete metamodel (fmp.ecore) as defined in Ecore.
Feature models are serialized according the this metamodel using standard EMF serializer. The root of the EMF resource is Project and contains model, metamodel and meta-metamodel. Every element of the feature model is a Node and contains other nodes as children. The feature model and all of its configurations are represented using the same metamodel. The origin-confs association links nodes from the model (i.e., origins) to nodes from the configuration (i.e., confs).

Features and references with max > 1 can be cloned. The prototype-clones association relates the original feature (i.e., the prototype) with its clones. Additionally, the clonables can have a configuration state which can be one of five states defined in ConfigState enumeration. The default state is UNDECIDED.
The feature-references association allows the reference to point at a feature and navigate from the feature to all references pointing at it. A feature contains a value represented by TypedValue. The fourth value type FEATURE is what we call a reference attribute, a mechanism allowing to select a feature from the configuration as a value of the attribute. A feature can also contain a Constraint in which case, the feature is the context of the constraint (i.e., the constraint may only refer to subfeatures of the context feature).

The metamodel allows configuring a subtree of any feature in the feature model in which case the feature is referred to as a root feature. A root feature contains its configurations, that is copies of its subtree, where elements are related using the origin-confs association. The configurations seen in the Properties view are contained by meta-elements (i.e., the properties of feature Catalog are the configuration of meta-feature Feature and are also contained by Feature). The root of nodes's properties is related with the node using the properties-describedNode association.

The infinite recursion caused by metacircularity is broken in the meta-metamodel nodes, which do not have properties, but use normal class attributes such as Feature.name, Node.min, Reference.feature.

The fmp.system.MetaModel class is used for the creation of initial model, metamodel and meta-metamodel. Function public static Project makeProject() is used by new model wizard to create the contents of an empty feature model.

Role Query

fmp.system.RoleQuery is a utility class used to determine the roles of a given Node. This is necessary because the same metamodel class is used to represent elements in conceptually different places. The following functions return constants defined in the RoleQuery class.

  • public int getLocationType(Node node) returns:
    CONFIGURATION,
    CONFIGURATION_PROPERTIES,
    MODEL,
    MODEL_PROPERTIES,
    METAMODEL,
    METAMODEL_PROPERTIES,
    METAMETAMODEL.
  • public int getNodeType(Node node) returns:
    UNDEFINED,
    ROOT_FEATURE,
    SOLITARY_FEATURE,
    GROUPED_FEATURE,
    SOLITARY_REFERENCE,
    GROUPED_REFERENCE,
    FEATURE_GROUP,
    FEATURE_MODEL.
  • public int getPropertyRole(Node node) returns:
    NONE,
    NAME,
    ID,
    MIN_OCCUR,
    MAX_OCCUR,
    DESCRIPTION,
    ATTRIBUTE,
    TYPE_GROUP,
    TYPE,
    VALUE,
    DEFAULT_VALUE,
    REFERENCED_FEATURE.

Model Navigation

fmp.system.ModelNavigation is a utility class used to navigate in the feature model tree.

  • public List getNodes(Node startingNode, String path)
    - Returns the node starting at the given node to the node pointed to the given path (of feature name). Works only across solitary features and grouped features. Note that this method will skip any feature group in between a solitary feature and a grouped feature. Returns null if no node was found. Use the ModelNavigation.PATH_SEPARATOR defined in this class. No PATH_SEPARATOR at the beginning of path.
  • public Node findNodeWithName(Node node, String name)
    - Returns the first node (closest to the initial argument) with the given name
  • public Feature navigateToRootFeature(Node node)
    - Returns the root feature (in the sense defined in RoleQuery) of a diagram containing the node or null for model, metamodel and meta-metamodel.
  • public Node navigateToFirstOrigin(Node node)
    - Returns its grand-grand...-grand origin node (the one that no longer has origin itself) of the given node.
  • public List getSelectedClonables(List clonables)
    - Returns nodes from the clonables list that are user or machine selected.

Model Manipulation

fmp.system.ModelManipulation is a utility class implementing common operation on the feature model. Functions copy, copyTree, copyNode, and remove work in two modes: instant or deferred. In the deferred mode, the CompoundCommand given as argument is used to accumulate individual modification commands. The modifications are applied during the execution of the command. In the instant mode, the command is null and the model is modified during the execution of the function.

  • public Node copy(Node node, EditingDomain domain, AdapterFactory adapterFactory, CompoundCommand command) - Creates a copy of a given node together with its children and properties. The copy is added as a sibling of the node.
  • public Node copy(Node node, EditingDomain domain, AdapterFactory adapterFactory, CompoundCommand command) - Creates a copy of each node in the tree. Traverses the tree recursively.
  • public Node copyNode(Node node, EditingDomain domain, AdapterFactory adapterFactory, CompoundCommand command) - Creates and returns a copy of a single node.
  • public Feature configure(Feature root) - Configures given root feature. Starts the recursion.
  • public Node configureTree(Node node) - Configures each node in the tree by calling configureNode(Node node). Traverses the tree recursively.
  • public void remove(Node node, EditingDomain domain, CompoundCommand command, boolean appendOnly) - Removes a given node together with its properties.

Commands

Package fmp.provider.command contains frequently used commands. The commands use functions from ModelManipulation class in the deferred mode.

  • CloneCommand - used to create clones of features in configuration.
  • CreateNodeCommand - used to create a new node as a child.
  • RemoveWithPropertiesCommand - used to remove a collection of nodes together with their properties.
  • SynchronizeCommand - used by 'Synchronize' action.
  • UnfoldReferenceCommand - used by 'Unfold Reference' action.

Model Access

Feature models (.fmp files) are serialized using standard EMF serializer and stored in XMI (the resource type is set to XMI in .genmodel). The root of the resource is an instance of Project class. fmp.util.FmpResourceImpl is the implementation of the resource for storing feature models. It is best to load resources using editing domain.

fmp.util.FmpExternalLoader class can be used to load multiple resources the same way the FmpEditor would. To load a resource use public void load(IFile file) or public void load(String fullPath) functions (where fullName is the same as IFile.getFullPath()). Retrieve the list of loaded resources using public EList getResources(). The root object of a resource can be retrieved using getAllContents().next(). In case of feature models, the root object can be cast to Project class.

The model should be modified using commands, which, in turn, can be executed on the command stack. The instance of the command stack can be obtained by calling getEditingDomain.getCommandStack(). Execute the command using getEditingDomain().getCommandStack().execute(Command command).

The model can be saved using public void save(int i) where i is the index of a resource to be saved.

Details of the fmp.util.FmpExternalLoader class.

  • public AdapterFactory getAdapterFactory()
  • public EditingDomain getEditingDomain()
  • public void load(IFile file)
  • public void load(String fullPath)
  • public EList getResources()
  • public void save(int i)