You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kh...@apache.org on 2016/07/02 20:49:33 UTC

maven git commit: [MNG-6056] Implement Feature Toggle Module to handle Feature Toggles o Implemented feature toggle module plus command line options etc. to activate feature and list available feature toggles. o Added example feature locations which

Repository: maven
Updated Branches:
  refs/heads/MNG-6056 [created] 1c4f3b25e


[MNG-6056] Implement Feature Toggle Module to handle Feature Toggles
 o Implemented feature toggle module plus command line options
   etc. to activate feature and list available feature toggles.
 o Added example feature locations which should be removed before
   really using it.


Project: http://git-wip-us.apache.org/repos/asf/maven/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/1c4f3b25
Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/1c4f3b25
Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/1c4f3b25

Branch: refs/heads/MNG-6056
Commit: 1c4f3b25e8ec4a42bede1b2912075c0f5ac530d9
Parents: c2018a4
Author: Karl Heinz Marbaise <kh...@apache.org>
Authored: Sat Jul 2 22:47:46 2016 +0200
Committer: Karl Heinz Marbaise <kh...@apache.org>
Committed: Sat Jul 2 22:47:46 2016 +0200

----------------------------------------------------------------------
 maven-core/pom.xml                              |   4 +
 .../java/org/apache/maven/DefaultMaven.java     |  16 ++
 .../apache/maven/graph/DefaultGraphBuilder.java |  10 +
 maven-embedder/pom.xml                          |   4 +
 .../java/org/apache/maven/cli/CLIManager.java   |   6 +
 .../java/org/apache/maven/cli/MavenCli.java     | 221 ++++++++++++-------
 .../java/org/apache/maven/cli/MavenCliTest.java |   2 +
 maven-feature/pom.xml                           |  62 ++++++
 .../apache/maven/feature/AvailableFeatures.java |  62 ++++++
 .../maven/feature/DefaultSelectedFeatures.java  |  75 +++++++
 .../apache/maven/feature/SelectedFeatures.java  |  56 +++++
 .../feature/DefaultSelectedFeaturesTest.java    |  58 +++++
 pom.xml                                         |   6 +
 13 files changed, 508 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-core/pom.xml
----------------------------------------------------------------------
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index adf63a6..ec35f98 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -38,6 +38,10 @@ under the License.
   </properties>
 
   <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-feature</artifactId>
+    </dependency>
     <!--  Maven -->
     <dependency>
       <groupId>org.apache.maven</groupId>

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index da17830..d2cabac 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -38,6 +38,8 @@ import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.feature.AvailableFeatures;
+import org.apache.maven.feature.SelectedFeatures;
 import org.apache.maven.graph.GraphBuilder;
 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
@@ -92,6 +94,9 @@ public class DefaultMaven
 
     @Requirement
     private DefaultRepositorySystemSessionFactory repositorySessionFactory;
+    
+    @Requirement
+    private SelectedFeatures selectedFeatures;
 
     @Requirement( hint = GraphBuilder.HINT )
     private GraphBuilder graphBuilder;
@@ -101,6 +106,17 @@ public class DefaultMaven
     {
         MavenExecutionResult result;
 
+        List<AvailableFeatures> activatedFeatures = selectedFeatures.getActiveFeatures();
+        if ( !activatedFeatures.isEmpty() )
+        {
+            logger.debug( "-------------------------------------------" );
+            for ( AvailableFeatures feature : activatedFeatures )
+            {
+                logger.debug( "Feature: " + feature.name() + " activated.");
+            }
+            logger.debug( "-------------------------------------------" );
+        }
+
         try
         {
             result = doExecute( request );

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 680d584..fc78f78 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -36,6 +36,8 @@ import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.feature.AvailableFeatures;
+import org.apache.maven.feature.SelectedFeatures;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.building.DefaultModelProblem;
 import org.apache.maven.model.building.ModelProblem;
@@ -65,6 +67,10 @@ public class DefaultGraphBuilder
 
     @Requirement
     protected ProjectBuilder projectBuilder;
+    
+    @Requirement
+    private SelectedFeatures selectedFeatures;
+    
 
     @Override
     public Result<ProjectDependencyGraph> build( MavenSession session )
@@ -74,6 +80,10 @@ public class DefaultGraphBuilder
             return dependencyGraph( session, session.getProjects(), false );
         }
         
+        if (selectedFeatures.isFeatureActive( AvailableFeatures.MNG10000 )) {
+            logger.info( " -> Features MNG 10000 is activated." );
+        }
+
         List<MavenProject> projects = session.getProjects();
 
         if ( projects == null )

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-embedder/pom.xml
----------------------------------------------------------------------
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index f9973c5..12fb613 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -36,6 +36,10 @@ under the License.
   <dependencies>
     <dependency>
       <groupId>org.apache.maven</groupId>
+      <artifactId>maven-feature</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
       <artifactId>maven-builder-support</artifactId>
     </dependency>
     <dependency>

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
index f461835..59c7446 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
@@ -100,6 +100,10 @@ public class CLIManager
     public static final String LEGACY_LOCAL_REPOSITORY = "llr";
 
     public static final String BUILDER = "b";
+    
+    public static final String LIST_FEATURES = "lf";
+    
+    public static final String ACTIVATE_FEATURES = "af";
 
     protected Options options;
 
@@ -140,6 +144,8 @@ public class CLIManager
         options.addOption( OptionBuilder.withLongOpt( "threads" ).hasArg().withDescription( "Thread count, for instance 2.0C where C is core multiplied" ).create( THREADS ) );
         options.addOption( OptionBuilder.withLongOpt( "legacy-local-repository" ).withDescription( "Use Maven 2 Legacy Local Repository behaviour, ie no use of _remote.repositories. Can also be activated by using -Dmaven.legacyLocalRepo=true" ).create( LEGACY_LOCAL_REPOSITORY ) );
         options.addOption( OptionBuilder.withLongOpt( "builder" ).hasArg().withDescription( "The id of the build strategy to use." ).create( BUILDER ) );
+        options.addOption( OptionBuilder.withLongOpt( "list-features" ).withDescription( "List the exiting features which can be activated." ).create( LIST_FEATURES) );
+        options.addOption( OptionBuilder.withLongOpt( "activate-features" ).withDescription( "Comma-delimited list of features to be actived." ).hasArg().create( ACTIVATE_FEATURES ) );
 
         // Adding this back in for compatibility with the verifier that hard codes this option.
         options.addOption( OptionBuilder.withLongOpt( "no-plugin-registry" ).withDescription( "Ineffective, only kept for backward compatibility" ).create( "npr" ) );

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 3e1194b..ec8c2c9 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -41,9 +41,11 @@ import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
+
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.UnrecognizedOptionException;
+import org.apache.commons.lang3.text.WordUtils;
 import org.apache.maven.BuildAbort;
 import org.apache.maven.InternalErrorException;
 import org.apache.maven.Maven;
@@ -78,6 +80,8 @@ import org.apache.maven.execution.MavenExecutionRequestPopulator;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.extension.internal.CoreExports;
 import org.apache.maven.extension.internal.CoreExtensionEntry;
+import org.apache.maven.feature.AvailableFeatures;
+import org.apache.maven.feature.SelectedFeatures;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.Repository;
@@ -103,13 +107,11 @@ import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.classworlds.ClassWorld;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.LoggerManager;
 import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-import com.google.inject.AbstractModule;
 import org.eclipse.aether.transfer.TransferListener;
 import org.slf4j.ILoggerFactory;
 import org.slf4j.Logger;
@@ -120,6 +122,11 @@ import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
 
+import com.google.common.base.Charsets;
+import com.google.common.base.Splitter;
+import com.google.common.io.Files;
+import com.google.inject.AbstractModule;
+
 // TODO: push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
 
 /**
@@ -185,6 +192,9 @@ public class MavenCli
     private Map<String, ConfigurationProcessor> configurationProcessors;
 
     private ProfileSelector profileSelector;
+    
+    @Requirement
+    private SelectedFeatures selectedFeatures;
 
     public MavenCli()
     {
@@ -226,8 +236,8 @@ public class MavenCli
     }
 
     /**
-     * This supports painless invocation by the Verifier during embedded execution of the core ITs.
-     * See <a href="http://maven.apache.org/shared/maven-verifier/xref/org/apache/maven/it/Embedded3xLauncher.html">
+     * This supports painless invocation by the Verifier during embedded execution of the core ITs. See
+     * <a href="http://maven.apache.org/shared/maven-verifier/xref/org/apache/maven/it/Embedded3xLauncher.html">
      * <code>Embedded3xLauncher</code> in <code>maven-verifier</code></a>
      */
     public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
@@ -354,8 +364,7 @@ public class MavenCli
             String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY );
             if ( basedirProperty == null )
             {
-                System.err.format(
-                    "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
+                System.err.format( "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
                 throw new ExitException( 1 );
             }
             File basedir = basedirProperty != null ? new File( basedirProperty ) : new File( "" );
@@ -446,6 +455,35 @@ public class MavenCli
             System.out.println( CLIReportingUtils.showVersion() );
             throw new ExitException( 0 );
         }
+
+        if ( cliRequest.commandLine.hasOption( CLIManager.LIST_FEATURES ) )
+        {
+            AvailableFeatures[] availableFeatures = AvailableFeatures.values();
+
+            System.out.println( "" );
+            System.out.println( "Currently existing feature toggles which you can enable:" );
+            System.out.println( "" );
+            System.out.println( "Issue     Option  Description" );
+            System.out.println( "--------- ------- ----------------------------------------------------" );
+            for ( AvailableFeatures feature : availableFeatures )
+            {
+                String wrappedString = WordUtils.wrap( feature.getDescription(), 60);
+                List<String> splitToList = Splitter.on( System.lineSeparator() ).splitToList( wrappedString );
+                for ( int i = 0; i < splitToList.size(); i++ )
+                {
+                    if (i == 0) {
+                       System.out.print (String.format( "%-9s %-8s", feature.getIssue(), feature.name()) + " "); 
+                    } else {
+                        System.out.print (String.format( "%-9s %-8s", "", "" ) + " ");
+                    }
+                    System.out.println( splitToList.get( i ));
+                }
+            }
+
+            System.out.println( "" );
+            System.out.println( "If you like to know more about a particular issue please visit: issues.apache.org/jira/browse/[ISSUE]" );
+            throw new ExitException( 0 );
+        }
     }
 
     /**
@@ -558,9 +596,8 @@ public class MavenCli
 
         ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
 
-        ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld ).setRealm(
-            containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true ).setName(
-            "maven" );
+        ContainerConfiguration cc =
+            new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld ).setRealm( containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true ).setName( "maven" );
 
         Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() );
         Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() );
@@ -598,6 +635,10 @@ public class MavenCli
 
         Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
 
+        //Explicitly startup lookup for the component, cause it's used during command line
+        //parsing etc.
+        selectedFeatures = container.lookup( SelectedFeatures.class );
+        
         eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
 
         DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
@@ -652,11 +693,11 @@ public class MavenCli
             }
 
             ContainerConfiguration cc = new DefaultContainerConfiguration() //
-                .setClassWorld( cliRequest.classWorld ) //
-                .setRealm( containerRealm ) //
-                .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
-                .setAutoWiring( true ) //
-                .setName( "maven" );
+            .setClassWorld( cliRequest.classWorld ) //
+            .setRealm( containerRealm ) //
+            .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
+            .setAutoWiring( true ) //
+            .setName( "maven" );
 
             DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
             {
@@ -722,7 +763,7 @@ public class MavenCli
     {
         CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
 
-        try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) )
+        try (InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ))
         {
 
             return parser.read( is ).getExtensions();
@@ -732,7 +773,7 @@ public class MavenCli
 
     private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
                                             List<CoreExtensionEntry> extensions )
-        throws Exception
+                                                throws Exception
     {
         if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
         {
@@ -828,8 +869,8 @@ public class MavenCli
 
             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
 
-            System.out.println(
-                cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
+            System.out.println( cipher.encryptAndDecorate( passwd,
+                                                           DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
 
             throw new ExitException( 0 );
         }
@@ -885,7 +926,7 @@ public class MavenCli
         throws Exception
     {
         if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY )
-                 || Boolean.getBoolean( "maven.legacyLocalRepo" ) )
+            || Boolean.getBoolean( "maven.legacyLocalRepo" ) )
         {
             cliRequest.request.setUseLegacyLocalRepository( true );
         }
@@ -904,9 +945,8 @@ public class MavenCli
         profileActivationContext.setInactiveProfileIds( request.getInactiveProfiles() );
         profileActivationContext.setSystemProperties( request.getSystemProperties() );
         profileActivationContext.setUserProperties( request.getUserProperties() );
-        profileActivationContext.setProjectDirectory( request.getPom() != null
-                                                          ? request.getPom().getParentFile()
-                                                          : null );
+        profileActivationContext.setProjectDirectory( request.getPom() != null ? request.getPom().getParentFile()
+                        : null );
 
         final List<ModelProblem> modelProblems = new ArrayList<>();
         final List<Profile> activeProfiles =
@@ -917,10 +957,12 @@ public class MavenCli
                                                         @Override
                                                         public void add( final ModelProblemCollectorRequest req )
                                                         {
-                                                            modelProblems.add( new DefaultModelProblem(
-                                                                    req.getMessage(), req.getSeverity(),
-                                                                    req.getVersion(), Profile.SOURCE_SETTINGS, -1, -1,
-                                                                    null, req.getException() ) );
+                                                            modelProblems.add( new DefaultModelProblem( req.getMessage(),
+                                                                                                        req.getSeverity(),
+                                                                                                        req.getVersion(),
+                                                                                                        Profile.SOURCE_SETTINGS,
+                                                                                                        -1, -1, null,
+                                                                                                        req.getException() ) );
 
                                                         }
 
@@ -949,14 +991,14 @@ public class MavenCli
                 {
                     try
                     {
-                        request.addRemoteRepository(
-                            MavenRepositorySystem.buildArtifactRepository( remoteRepository ) );
+                        request.addRemoteRepository( MavenRepositorySystem.buildArtifactRepository( remoteRepository ) );
 
                     }
                     catch ( final InvalidRepositoryException e )
                     {
                         slf4jLogger.warn( String.format( "Failure adding repository '%s' from profile '%s'.",
-                                                         remoteRepository.getId(), profile.getId() ), e );
+                                                         remoteRepository.getId(), profile.getId() ),
+                                          e );
 
                     }
                 }
@@ -967,14 +1009,14 @@ public class MavenCli
                 {
                     try
                     {
-                        request.addPluginArtifactRepository(
-                            MavenRepositorySystem.buildArtifactRepository( pluginRepository ) );
+                        request.addPluginArtifactRepository( MavenRepositorySystem.buildArtifactRepository( pluginRepository ) );
 
                     }
                     catch ( InvalidRepositoryException e )
                     {
                         slf4jLogger.warn( String.format( "Failure adding plugin repository '%s' from profile '%s'.",
-                                                         pluginRepository.getId(), profile.getId() ), e );
+                                                         pluginRepository.getId(), profile.getId() ),
+                                          e );
 
                     }
                 }
@@ -1032,7 +1074,7 @@ public class MavenCli
             {
                 slf4jLogger.error( "" );
                 slf4jLogger.error( "For more information about the errors and possible solutions"
-                                       + ", please read the following articles:" );
+                    + ", please read the following articles:" );
 
                 for ( Map.Entry<String, String> entry : references.entrySet() )
                 {
@@ -1044,8 +1086,7 @@ public class MavenCli
             {
                 slf4jLogger.error( "" );
                 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
-                slf4jLogger.error( buffer().strong().a( "  mvn <goals> -rf :" )
-                                   .a( project.getArtifactId() ).reset().toString() );
+                slf4jLogger.error( buffer().strong().a( "  mvn <goals> -rf :" ).a( project.getArtifactId() ).reset().toString() );
             }
 
             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
@@ -1100,8 +1141,8 @@ public class MavenCli
         {
             String line = indent + lines[i].trim();
 
-            if ( ( i == lines.length - 1 ) && ( showErrors
-                || ( summary.getException() instanceof InternalErrorException ) ) )
+            if ( ( i == lines.length - 1 )
+                && ( showErrors || ( summary.getException() instanceof InternalErrorException ) ) )
             {
                 slf4jLogger.error( line, summary.getException() );
             }
@@ -1168,9 +1209,9 @@ public class MavenCli
             //
             // There are too many ConfigurationProcessors so we don't know which one to run so report the error.
             //
-            StringBuilder sb = new StringBuilder(
-                String.format( "\nThere can only be one user supplied ConfigurationProcessor, there are %s:\n\n",
-                               userSuppliedConfigurationProcessorCount ) );
+            StringBuilder sb =
+                new StringBuilder( String.format( "\nThere can only be one user supplied ConfigurationProcessor, there are %s:\n\n",
+                                                  userSuppliedConfigurationProcessorCount ) );
             for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
             {
                 String hint = entry.getKey();
@@ -1199,8 +1240,8 @@ public class MavenCli
 
             if ( !userToolchainsFile.isFile() )
             {
-                throw new FileNotFoundException(
-                    "The specified user toolchains file does not exist: " + userToolchainsFile );
+                throw new FileNotFoundException( "The specified user toolchains file does not exist: "
+                    + userToolchainsFile );
             }
         }
         else
@@ -1218,8 +1259,8 @@ public class MavenCli
 
             if ( !globalToolchainsFile.isFile() )
             {
-                throw new FileNotFoundException(
-                    "The specified global toolchains file does not exist: " + globalToolchainsFile );
+                throw new FileNotFoundException( "The specified global toolchains file does not exist: "
+                    + globalToolchainsFile );
             }
         }
         else
@@ -1242,11 +1283,10 @@ public class MavenCli
 
         eventSpyDispatcher.onEvent( toolchainsRequest );
 
-        slf4jLogger.debug(
-            "Reading global toolchains from " + getLocation( toolchainsRequest.getGlobalToolchainsSource(),
-                                                             globalToolchainsFile ) );
-        slf4jLogger.debug( "Reading user toolchains from " + getLocation( toolchainsRequest.getUserToolchainsSource(),
-                                                                          userToolchainsFile ) );
+        slf4jLogger.debug( "Reading global toolchains from "
+            + getLocation( toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile ) );
+        slf4jLogger.debug( "Reading user toolchains from "
+            + getLocation( toolchainsRequest.getUserToolchainsSource(), userToolchainsFile ) );
 
         ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest );
 
@@ -1296,7 +1336,7 @@ public class MavenCli
             if ( commandLine.hasOption( deprecatedOption ) )
             {
                 slf4jLogger.warn( "Command line option -" + deprecatedOption
-                                      + " is deprecated and will be removed in future Maven versions." );
+                    + " is deprecated and will be removed in future Maven versions." );
             }
         }
 
@@ -1450,19 +1490,20 @@ public class MavenCli
             userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE;
         }
 
-        request.setBaseDirectory( baseDirectory ).setGoals( goals ).setSystemProperties(
-            cliRequest.systemProperties ).setUserProperties( cliRequest.userProperties ).setReactorFailureBehavior(
-            reactorFailureBehaviour ) // default: fail fast
-            .setRecursive( recursive ) // default: true
-            .setShowErrors( showErrors ) // default: false
-            .addActiveProfiles( activeProfiles ) // optional
-            .addInactiveProfiles( inactiveProfiles ) // optional
-            .setExecutionListener( executionListener ).setTransferListener(
-            transferListener ) // default: batch mode which goes along with interactive
-            .setUpdateSnapshots( updateSnapshots ) // default: false
-            .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false
-            .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn
-            .setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
+        request.setBaseDirectory( baseDirectory ).setGoals( goals ).setSystemProperties( cliRequest.systemProperties ).setUserProperties( cliRequest.userProperties ).setReactorFailureBehavior( reactorFailureBehaviour ) // default:
+                                                                                                                                                                                                                           // fail
+                                                                                                                                                                                                                           // fast
+        .setRecursive( recursive ) // default: true
+        .setShowErrors( showErrors ) // default: false
+        .addActiveProfiles( activeProfiles ) // optional
+        .addInactiveProfiles( inactiveProfiles ) // optional
+        .setExecutionListener( executionListener ).setTransferListener( transferListener ) // default: batch mode which
+                                                                                           // goes along with
+                                                                                           // interactive
+        .setUpdateSnapshots( updateSnapshots ) // default: false
+        .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false
+        .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn
+        .setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
 
         if ( alternatePomFile != null )
         {
@@ -1531,18 +1572,18 @@ public class MavenCli
             request.setExcludedProjects( exclProjects );
         }
 
-        if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && !commandLine.hasOption(
-            CLIManager.ALSO_MAKE_DEPENDENTS ) )
+        if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
+            && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
         {
             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM );
         }
-        else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption(
-            CLIManager.ALSO_MAKE_DEPENDENTS ) )
+        else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE )
+            && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
         {
             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM );
         }
-        else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption(
-            CLIManager.ALSO_MAKE_DEPENDENTS ) )
+        else if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
+            && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
         {
             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH );
         }
@@ -1570,10 +1611,13 @@ public class MavenCli
         // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to
         // extend the command line to accept its own configuration parameters.
         //
-        final String threadConfiguration = commandLine.hasOption( CLIManager.THREADS )
-            ? commandLine.getOptionValue( CLIManager.THREADS )
-            : request.getSystemProperties().getProperty(
-                MavenCli.THREADS_DEPRECATED ); // TODO: Remove this setting. Note that the int-tests use it
+        final String threadConfiguration =
+            commandLine.hasOption( CLIManager.THREADS ) ? commandLine.getOptionValue( CLIManager.THREADS )
+                            : request.getSystemProperties().getProperty( MavenCli.THREADS_DEPRECATED ); // TODO: Remove
+                                                                                                        // this setting.
+                                                                                                        // Note that the
+                                                                                                        // int-tests use
+                                                                                                        // it
 
         if ( threadConfiguration != null )
         {
@@ -1600,6 +1644,35 @@ public class MavenCli
             request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER ) );
         }
 
+        if ( commandLine.hasOption( CLIManager.ACTIVATE_FEATURES ) )
+        {
+            String activateFeaturesOptionValue = commandLine.getOptionValue( CLIManager.ACTIVATE_FEATURES );
+
+            List<AvailableFeatures> activatedFeatures = new ArrayList<>();
+
+            if ( activateFeaturesOptionValue != null )
+            {
+                StringTokenizer featureTokens = new StringTokenizer( activateFeaturesOptionValue, "," );
+
+                while ( featureTokens.hasMoreTokens() )
+                {
+                    String featureToken = featureTokens.nextToken().trim();
+
+                    try
+                    {
+                        AvailableFeatures resultingFeature = AvailableFeatures.valueOf( featureToken.toUpperCase() );
+                        activatedFeatures.add( resultingFeature );
+                    }
+                    catch ( java.lang.IllegalArgumentException e )
+                    {
+                        slf4jLogger.warn( "The requested feature '" + featureToken + "' Does not exist." );
+                    }
+                }
+            }
+
+            selectedFeatures.setActivatedFeatures( activatedFeatures );
+        }
+
         return request;
     }
 

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index c8d75b1..6bd5f5b 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -24,6 +24,7 @@ import java.io.File;
 import junit.framework.TestCase;
 
 import org.apache.commons.cli.ParseException;
+import org.apache.maven.feature.AvailableFeatures;
 
 public class MavenCliTest
     extends TestCase
@@ -107,4 +108,5 @@ public class MavenCliTest
 
         }
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-feature/pom.xml
----------------------------------------------------------------------
diff --git a/maven-feature/pom.xml b/maven-feature/pom.xml
new file mode 100644
index 0000000..0ddd5fc
--- /dev/null
+++ b/maven-feature/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<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>
+
+  <parent>
+    <groupId>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>3.4.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-feature</artifactId>
+
+  <name>Maven Feature</name>
+  <description>Feature Toggle Module. Can be used in any other module.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.sisu</groupId>
+      <artifactId>org.eclipse.sisu.plexus</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-component-annotations</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-component-metadata</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-feature/src/main/java/org/apache/maven/feature/AvailableFeatures.java
----------------------------------------------------------------------
diff --git a/maven-feature/src/main/java/org/apache/maven/feature/AvailableFeatures.java b/maven-feature/src/main/java/org/apache/maven/feature/AvailableFeatures.java
new file mode 100644
index 0000000..473a40c
--- /dev/null
+++ b/maven-feature/src/main/java/org/apache/maven/feature/AvailableFeatures.java
@@ -0,0 +1,62 @@
+package org.apache.maven.feature;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a>
+ *
+ * @since 3.4.0
+ */
+public enum AvailableFeatures
+{
+
+    //FIXME: Only some examples given. Nothing which exists in reality.
+
+    MNG9991( "MNG-9991", "First Feature to be toggable via command line option. "
+        + "First Feature to be toggable via command line option." ),
+    MNG9992( "MNG-9992", "First Feature to be toggable via command line option. "
+        + "First Feature to be toggable via command line option. XX asdfa. asdf dsf." ),
+    MNG9993( "MNG-9993", "First Feature to be toggable via command line option. "
+        + "More text than you think." ),
+    MNG10000( "MNG-10000", "First Feature to be toggable via command line option. "
+        + "Here much more than you thing." );
+
+//    UNKNONW ("UNKNOWN", "The unknown feature.");
+
+    private String issue;
+
+    private String description;
+
+    private AvailableFeatures( String issue, String description )
+    {
+        this.issue = issue;
+        this.description = description;
+    }
+
+    public String getDescription()
+    {
+        return this.description;
+    }
+
+    public String getIssue()
+    {
+        return this.issue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-feature/src/main/java/org/apache/maven/feature/DefaultSelectedFeatures.java
----------------------------------------------------------------------
diff --git a/maven-feature/src/main/java/org/apache/maven/feature/DefaultSelectedFeatures.java b/maven-feature/src/main/java/org/apache/maven/feature/DefaultSelectedFeatures.java
new file mode 100644
index 0000000..cc11462
--- /dev/null
+++ b/maven-feature/src/main/java/org/apache/maven/feature/DefaultSelectedFeatures.java
@@ -0,0 +1,75 @@
+package org.apache.maven.feature;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+@Component( instantiationStrategy = "singleton", role = SelectedFeatures.class )
+public class DefaultSelectedFeatures
+    implements SelectedFeatures
+{
+    @Requirement
+    private Logger logger;
+
+    private List<AvailableFeatures> activatedFeatures;
+
+    @Override
+    public void setActivatedFeatures( List<AvailableFeatures> featuresToBeActivated )
+    {
+        if ( featuresToBeActivated == null )
+        {
+            this.activatedFeatures = new ArrayList<>();
+        }
+        else
+        {
+            this.activatedFeatures = featuresToBeActivated;
+        }
+    }
+
+    @Override
+    public boolean isFeatureActive( AvailableFeatures feature )
+    {
+        if ( activatedFeatures != null )
+        {
+            return activatedFeatures.contains( feature );
+        }
+        return false;
+    }
+
+    @Override
+    public List<AvailableFeatures> getActiveFeatures()
+    {
+        if ( activatedFeatures == null )
+        {
+            return Collections.emptyList();
+        }
+        else
+        {
+            return activatedFeatures;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-feature/src/main/java/org/apache/maven/feature/SelectedFeatures.java
----------------------------------------------------------------------
diff --git a/maven-feature/src/main/java/org/apache/maven/feature/SelectedFeatures.java b/maven-feature/src/main/java/org/apache/maven/feature/SelectedFeatures.java
new file mode 100644
index 0000000..6f6007a
--- /dev/null
+++ b/maven-feature/src/main/java/org/apache/maven/feature/SelectedFeatures.java
@@ -0,0 +1,56 @@
+package org.apache.maven.feature;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+
+/**
+ * This gives access to the feature storage which can be used during the 
+ * run of Maven to access information about the activated features.
+ * 
+ * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a>
+ *
+ * @since 3.4.0
+ */
+public interface SelectedFeatures
+{
+
+    /**
+     * @since 3.4.0
+     * @return The list of features which will be activated.
+     */
+    void setActivatedFeatures(List<AvailableFeatures> activatedFeatures);
+
+    /**
+     * @param feature The feature to check for if it is activated or not.
+     * @return <code>true</code> in case of feature has been activated via command line.
+     * <code>--activate-feature FEATURE</code> <code>false</code> otherwise.
+     * @since 3.4.0
+     */
+    boolean isFeatureActive(AvailableFeatures feature);
+    
+    /**
+     * @return The list of features which are activated.
+     * @since 3.4.0
+     */
+    List<AvailableFeatures> getActiveFeatures();
+    
+
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/maven-feature/src/test/java/org/apache/maven/feature/DefaultSelectedFeaturesTest.java
----------------------------------------------------------------------
diff --git a/maven-feature/src/test/java/org/apache/maven/feature/DefaultSelectedFeaturesTest.java b/maven-feature/src/test/java/org/apache/maven/feature/DefaultSelectedFeaturesTest.java
new file mode 100644
index 0000000..0790134
--- /dev/null
+++ b/maven-feature/src/test/java/org/apache/maven/feature/DefaultSelectedFeaturesTest.java
@@ -0,0 +1,58 @@
+package org.apache.maven.feature;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class DefaultSelectedFeaturesTest
+{
+
+    @Test
+    public void getActiveFeaturesShouldNotReturnNull()
+    {
+        DefaultSelectedFeatures sf = new DefaultSelectedFeatures();
+        assertNotNull( sf.getActiveFeatures() );
+        assertEquals( sf.getActiveFeatures().size(), 0 );
+    }
+
+    @Test
+    public void isFeatureActiveShouldReturnFalse()
+    {
+        DefaultSelectedFeatures sf = new DefaultSelectedFeatures();
+        assertFalse( sf.isFeatureActive( AvailableFeatures.MNG10000 ) );
+    }
+
+    @Test
+    public void isFeatureActiveShouldReturnFalseIfNotTheCorrectFeatureIsActivated()
+    {
+        DefaultSelectedFeatures sf = new DefaultSelectedFeatures();
+
+        sf.setActivatedFeatures( Arrays.asList( AvailableFeatures.MNG9991, AvailableFeatures.MNG9992 ) );
+        assertFalse( sf.isFeatureActive( AvailableFeatures.MNG10000 ) );
+        assertTrue( sf.isFeatureActive( AvailableFeatures.MNG9991 ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/1c4f3b25/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c447507..4e4ec05 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,7 @@ under the License.
   </properties>
 
   <modules>
+    <module>maven-feature</module>
     <module>maven-plugin-api</module>
     <module>maven-builder-support</module>
     <module>maven-model</module>
@@ -165,6 +166,11 @@ under the License.
   <dependencyManagement>
     <!--bootstrap-end-comment-->
     <dependencies>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-feature</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <!--  Maven Modules -->
       <!--bootstrap-start-comment-->
       <dependency>