-
Notifications
You must be signed in to change notification settings - Fork 0
Usage
The feature-gen project uses the model files created with the FeatureIDE to generate your features and variants as a simple Java API. There are currently two ways to generate the code: Either you use the Xtend based active annotations or you use the standalone generators, which can be called as simple Java applications. Regardless of which way you prefer, you always get the same Java API.
feature-gen generates the following elements from the feature model file:
- <RootFeatureName>Feature: An enumeration containing all features from your feature model.
- <RootFeatureName>FeatureCheckService: A service to check whether a given feature is active or not.
- <RootFeatureName>SelectedFeatures: An annotation used by the variants.
- <RootFeatureName>Variant: A marker interface used by the variants. Each configuration model file will be generated into a single variant class.
The first two elements are the most important ones, as they are the actual API to check the features in your application. You can create new feature check services from a given variant with the static method of.
RootFeatureCheckService featureCheckService = RootFeatureCheckService.of( Variant1.class );
if ( featureCheckService.isFeatureActive( RootFeature.MY_FEATURE ) ) {
...
}
You can also create a check service without any features by using the static method empty. Such a service will always return false to calls to isFeatureActive. This is useful if your application has some baseline functionality that can be used without any variation.
RootFeatureCheckService featureCheckService = RootFeatureCheckService.empty( );
Note that the feature check services, once created, are immutable and thus inherent thread safe.
Additional to this Wiki entry, please consult also the project's JavaDoc.
The general approach of feature-gen using the active annotations is as following. We are using Xtend's active annotations to parse the model files from your FeatureIDE project and to generate all required classes to actually use the feature model in your application. You therefore usually have one Xtend class annotated with FeatureIDEFeatures (referencing the feature file) and multiple Xtend classes annotated with FeatureIDEVariant (referencing the configuration files).
In order to use feature-gen in your project, simply add the Maven dependencies to your pom.xml. The library requires Java 8 and Xtend 2.14 or newer.
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-lib</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-annotation-processor</artifactId>
<version>2.0.0</version>
</dependency>
That does not mean that you have to use Xtend throughout in your whole application. We recommend that you create a single (Maven) module for the features and the variants and have only there a dependency to the annotation processor of feature-gen. Keep also in mind that there are no dependencies from the generated classes to feature-gen. You can therefore use the annotation processor with the provided scope. The runtime library (featuregen-lib) has to be available in the classpath though.
If you do not specify any parameters, feature-gen assumes that your feature model is located in a file named model.xml next to the annotated class.
@FeatureIDEFeatures
class Features {
}
If this is not the case, you can specify the path with the value parameter of the annotation. If you do not use a slash, it is assumed that the path is relative to the annotated class. If you do use a slash, it is assumed that the path is relative to the containing source folder.
@FeatureIDEFeatures('/path/to/model/file.xml')
class Features {
}
Please note: Due to restrictions of the active annotations, the file must be contained in the same project and the same source folder as the annotated class.
Per default, the generated features will have the suffix _FEATURE. You can overwrite this behavior by specifying the parameters prefix and/or suffix.
@FeatureIDEFeatures(prefix='PREFIX_', suffix='_SUFFIX')
class Features {
}
If you do not specify any parameters, feature-gen assumes that the configuration model for your variant is located in a xml file with the same name as the annotated class next to it. However, you must always specify the featuresClass value. This class must point to the class that is annotated with FeatureIDEFeatures. Following variant would expect a file named Variant1.xml next to the class.
@FeatureIDEVariant(featuresClass=Features)
class Variant1 {
}
If this is not the case, you can specify the path with the value parameter of the annotation. If you do not use a slash, it is assumed that the path is relative to the annotated class. If you do use a slash, it is assumed that the path is relative to the containing source folder.
@FeatureIDEVariant(featuresClass=Features, value='/path/to/model/file.xml')
class Variant1{
}
Please note: Due to restrictions of the active annotations, the file must be contained in the same project and the same source folder as the annotated class.
Additional to this Wiki entry, please consult also the project's JavaDoc.
In order to use the standalone generator from feature-gen in your project, you need to add the Maven dependencies to your project.
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-generator</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-lib</artifactId>
<version>2.0.0</version>
</dependency>
The featuregen-generator is only required during the build process. Only featuregen-lib has to available in the classpath during runtime.
You can now call the classes FeatureIDEFeaturesGenerator and FeatureIDEVariantGenerator as Java applications and generate the features and variants from your models.
The FeatureIDEFeaturesGenerator requires at least three parameters:
- The path to the FeatureIDE feature model file.
- The path to the output folder.
- The package name of the newly generated classes.
- Optionally you can also provide the prefix and suffix which are appended to each feature.
The FeatureIDEVariantGenerator requires at least six parameters:
- The path to the FeatureIDE configuration model file.
- The path to the feature model file.
- The path to the output folder.
- The package name of the newly generated variant.
- The simple class name of the new variant.
- The package name of the features.
- Optionally you can also provide the prefix and suffix which are appended to each feature.
An easy way to include the generator in your IDE is to use the exec-maven-plugin. The following example assumes that your src/main/resources folder contains the FeatureIDE model file and two variant model files. For the lifecycle mapping we assume that you use Eclipse with the m2e plugin.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.rhocas.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-lib</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<dependencies>
<dependency>
<groupId>de.rhocas.featuregen</groupId>
<artifactId>featuregen-generator</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<configuration>
<includePluginDependencies>true</includePluginDependencies>
</configuration>
<executions>
<execution>
<id>generateFeatures</id>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>de.rhocas.featuregen.generator.FeatureIDEFeaturesGenerator</mainClass>
<arguments>
<argument>${project.basedir}/src/main/resources/model.xml</argument>
<argument>${project.build.directory}/generated-sources</argument>
<argument>de.rhocas.featuregen.ap.test.feature</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>generateVariant1</id>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>de.rhocas.featuregen.generator.FeatureIDEVariantGenerator</mainClass>
<arguments>
<argument>${project.basedir}/src/main/resources/Variant1.xml</argument>
<argument>${project.basedir}/src/main/resources/model.xml</argument>
<argument>${project.build.directory}/generated-sources</argument>
<argument>de.rhocas.featuregen.ap.test.variant</argument>
<argument>Variant1</argument>
<argument>de.rhocas.featuregen.ap.test.feature</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>generateVariant2</id>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>de.rhocas.featuregen.generator.FeatureIDEVariantGenerator</mainClass>
<arguments>
<argument>${project.basedir}/src/main/resources/Variant2.xml</argument>
<argument>${project.basedir}/src/main/resources/model.xml</argument>
<argument>${project.build.directory}/generated-sources</argument>
<argument>de.rhocas.featuregen.ap.test.variant</argument>
<argument>Variant2</argument>
<argument>de.rhocas.featuregen.ap.test.feature</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>addGeneratedSourceFolder</id>
<goals>
<goal>add-source</goal>
</goals>
<phase>process-sources</phase>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<versionRange>[1,)</versionRange>
<goals>
<goal>java</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnIncremental>true</runOnIncremental>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Various examples can be found here.