This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-slingfeature-maven-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 47108ec  SLING-7961 : Adjust feature file reading to latest state
47108ec is described below

commit 47108ec09ddce3a3f615f06dc977085b4ad4dd9b
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri Sep 28 13:52:25 2018 +0200

    SLING-7961 : Adjust feature file reading to latest state
---
 .../feature/maven/ApplicationProjectConfig.java    | 116 -------
 .../feature/maven/ApplicationProjectInfo.java      |  31 --
 .../apache/sling/feature/maven/Environment.java    |   8 +-
 .../sling/feature/maven/FeatureConstants.java      |   8 -
 .../sling/feature/maven/FeatureProjectConfig.java  |  59 ++--
 .../sling/feature/maven/FeatureProjectInfo.java    |  17 +-
 .../apache/sling/feature/maven/Preprocessor.java   | 379 +++++++--------------
 .../apache/sling/feature/maven/ProjectHelper.java  | 103 +-----
 .../apache/sling/feature/maven/ProjectInfo.java    |  27 --
 .../feature/maven/{mojos => }/Substitution.java    |  29 +-
 .../feature/maven/mojos/AbstractFeatureMojo.java   |  37 +-
 .../feature/maven/mojos/AggregateFeatures.java     |  39 ++-
 .../{AttachFeature.java => AttachFeatures.java}    |  78 ++---
 .../mojos/DependencyLifecycleParticipant.java      |  10 +-
 .../feature/maven/mojos/GenerateResources.java     |  60 ----
 src/main/resources/META-INF/plexus/components.xml  |  83 +----
 .../feature/maven/mojos/AggregateFeaturesTest.java |  51 ++-
 .../feature/maven/mojos/AttachFeatureTest.java     |  26 +-
 .../feature/maven/mojos/GenerateResourceTest.java  | 108 ------
 19 files changed, 278 insertions(+), 991 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java 
b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
deleted file mode 100644
index 78cd363..0000000
--- a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.feature.maven;
-
-import org.apache.maven.artifact.Artifact;
-
-public class ApplicationProjectConfig {
-
-    public static final String CFG_FEATURES = "features";
-
-    public static final String CFG_TEST_FEATURES = "testFeatures";
-
-    public static final String CFG_FEATURE_REFS = "featureRefs";
-
-    public static final String CFG_TEST_FEATURE_REFS = "testFeatureRefs";
-
-    public static final String DEFAULT_FEATURE_DIR = "src/main/osgi/features";
-
-    public static final String DEFAULT_TEST_FEATURE_DIR = 
"src/test/osgi/features";
-
-    public static final String DEFAULT_REF_DIR = "src/main/osgi/feature-refs";
-
-    public static final String DEFAULT_TEST_REF_DIR = 
"src/test/osgi/feature-refs";
-
-    private final String featuresDirName;
-
-    private final String featureRefsDirName;
-
-    private final boolean skipAddDep;
-
-    private final String name;
-
-    private final String scope;
-
-    private final boolean isTest;
-
-    public static ApplicationProjectConfig getMainConfig(final 
ApplicationProjectInfo info) {
-        return new ApplicationProjectConfig(info, false);
-    }
-
-    public static ApplicationProjectConfig getTestConfig(final 
ApplicationProjectInfo info) {
-        return new ApplicationProjectConfig(info, true);
-    }
-
-    private ApplicationProjectConfig(final ApplicationProjectInfo info, final 
boolean test) {
-        this.isTest = test;
-        final String featuresDirCfgName;
-        final String featureRefsDirCfgName;
-        final String defaultDir;
-        final String defaultRefDir;
-        final String skipAddDepCfgName;
-        final String defaultSkipValue;
-        if ( test ) {
-            featuresDirCfgName = CFG_TEST_FEATURES;
-            featureRefsDirCfgName = CFG_TEST_FEATURE_REFS;
-            defaultDir = DEFAULT_TEST_FEATURE_DIR;
-            defaultRefDir = DEFAULT_TEST_REF_DIR;
-            skipAddDepCfgName = 
FeatureProjectConfig.CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES;
-            defaultSkipValue = "true";
-            this.scope = Artifact.SCOPE_TEST;
-            this.name = "test features";
-        } else {
-            featuresDirCfgName = CFG_FEATURES;
-            featureRefsDirCfgName = CFG_FEATURE_REFS;
-            defaultDir = DEFAULT_FEATURE_DIR;
-            defaultRefDir = DEFAULT_REF_DIR;
-            skipAddDepCfgName = 
FeatureProjectConfig.CFG_SKIP_ADD_FEATURE_DEPENDENCIES;
-            defaultSkipValue = "false";
-            this.scope = Artifact.SCOPE_PROVIDED;
-            this.name = "features";
-        }
-        this.featuresDirName = ProjectHelper.getConfigValue(info.plugin, 
featuresDirCfgName, defaultRefDir);
-        this.featureRefsDirName = ProjectHelper.getConfigValue(info.plugin, 
featureRefsDirCfgName, defaultDir);
-        final String skipCfg = ProjectHelper.getConfigValue(info.plugin, 
skipAddDepCfgName, defaultSkipValue);
-        this.skipAddDep = "true".equals(skipCfg.toLowerCase());
-    }
-
-    public String getName() {
-        return this.name;
-    }
-
-    public String getFeatureDir() {
-        return this.featuresDirName;
-    }
-
-    public String getFeatureRefDir() {
-        return this.featuresDirName;
-    }
-
-    public boolean isSkipAddDependencies() {
-        return this.skipAddDep;
-    }
-
-    public String getScope() {
-        return this.scope;
-    }
-
-    public boolean isTestConfig() {
-        return this.isTest;
-    }
-}
-
diff --git 
a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java 
b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
deleted file mode 100644
index dc0e393..0000000
--- a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.feature.maven;
-
-import org.apache.sling.feature.Feature;
-
-import java.util.List;
-
-public class ApplicationProjectInfo extends ProjectInfo {
-
-    public List<Feature> features;
-    public List<Feature> testFeatures;
-
-    public List<Feature> assembledFeatures;
-    public List<Feature> assembledTestFeatures;
-}
-
diff --git a/src/main/java/org/apache/sling/feature/maven/Environment.java 
b/src/main/java/org/apache/sling/feature/maven/Environment.java
index ca5592d..69e79e7 100644
--- a/src/main/java/org/apache/sling/feature/maven/Environment.java
+++ b/src/main/java/org/apache/sling/feature/maven/Environment.java
@@ -16,20 +16,20 @@
  */
 package org.apache.sling.feature.maven;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 import org.apache.maven.execution.MavenSession;
 import org.codehaus.plexus.logging.Logger;
 
-import java.util.HashMap;
-import java.util.Map;
-
 public class Environment {
 
     public ArtifactHandlerManager artifactHandlerManager;
     public ArtifactResolver resolver;
     public MavenSession session;
     public Logger logger;
-    public final Map<String, ProjectInfo> modelProjects = new HashMap<>();
+    public final Map<String, FeatureProjectInfo> modelProjects = new 
HashMap<>();
 }
 
diff --git a/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java 
b/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
index e5d1a0b..61dfed1 100644
--- a/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
@@ -20,15 +20,7 @@ public abstract class FeatureConstants {
 
     public static final String PACKAGING_FEATURE = "slingfeature";
 
-    public static final String PACKAGING_APPLICATION = "osgiapp";
-
     public static final String CLASSIFIER_FEATURE = "feature";
 
     public static final String CLASSIFIER_TEST_FEATURE = "testfeature";
-
-    public static final String FEATURE_ARTIFACT_NAME = "feature.json";
-
-    public static final String FEATURE_PROCESSED_LOCATION = 
"/features/processed";
-
-    public static final String TEST_FEATURE_ARTIFACT_NAME = "testfeature.json";
 }
diff --git 
a/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java 
b/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java
index a9ba4f5..137b47d 100644
--- a/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java
@@ -20,33 +20,26 @@ import org.apache.maven.artifact.Artifact;
 
 public class FeatureProjectConfig {
 
-    public static final String CFG_SKIP_ADD_FEATURE_DEPENDENCIES = 
"skipAddFeatureDependencies";
-
-    public static final String CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES = 
"skipAddTestFeatureDependencies";
+    public static final String CFG_FEATURES = "features";
 
-    public static final String CFG_FEATURE_FILE = "featureFile";
+    public static final String CFG_TEST_FEATURES = "testFeatures";
 
-    public static final String CFG_TEST_FEATURE_FILE = "testFeatureFile";
-
-    public static final String CFG_FEATURE_INLINED = "feature";
+    public static final String CFG_SKIP_ADD_FEATURE_DEPENDENCIES = 
"skipAddFeatureDependencies";
 
-    public static final String CFG_TEST_FEATURE_INLINED = "testFeature";
+    public static final String CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES = 
"skipAddTestFeatureDependencies";
 
     public static final String CFG_SKIP_ADD_JAR_TO_FEATURE = 
"skipAddJarToFeature";
 
     public static final String CFG_SKIP_ADD_JAR_TO_TEST_FEATURE = 
"skipAddJarToTestFeature";
 
-    public static final String CFG_JAR_START_LEVEL = "jarStartLevel";
+    public static final String CFG_JAR_START_ORDER = "jarStartOrder";
 
-    public static final String DEFAULT_FEATURE_FILE = 
"src/main/osgi/feature.json";
 
-    public static final String DEFAULT_TEST_FEATURE_FILE = 
"src/test/osgi/feature.json";
+    public static final String DEFAULT_FEATURE_DIR = "src/main/features";
 
-    public static final String DEFAULT_START_LEVEL = "20";
+    public static final String DEFAULT_TEST_FEATURE_DIR = 
"src/test/osgi/features";
 
-    private final String inlinedFeature;
-
-    private final String featureFileName;
+    private final String featuresDirName;
 
     private final boolean skipAddDep;
 
@@ -56,7 +49,7 @@ public class FeatureProjectConfig {
 
     private final boolean isTest;
 
-    private final String jarStartLevel;
+    private final String jarStartOrder;
 
     private final boolean skipAddJar;
 
@@ -70,47 +63,39 @@ public class FeatureProjectConfig {
 
     private FeatureProjectConfig(final FeatureProjectInfo info, final boolean 
test) {
         this.isTest = test;
-        final String inlineCfgName;
-        final String fileCfgName;
-        final String defaultFile;
+        final String featuresDirCfgName;
+        final String defaultDir;
         final String skipAddDepCfgName;
         final String defaultSkipValue;
         if ( test ) {
-            inlineCfgName = CFG_TEST_FEATURE_INLINED;
-            fileCfgName = CFG_TEST_FEATURE_FILE;
-            defaultFile = DEFAULT_TEST_FEATURE_FILE;
+            featuresDirCfgName = CFG_TEST_FEATURES;
+            defaultDir = DEFAULT_TEST_FEATURE_DIR;
             this.scope = Artifact.SCOPE_TEST;
             skipAddDepCfgName = CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES;
             defaultSkipValue = "true";
             this.name = "test feature";
             this.skipAddJar = 
"true".equals(ProjectHelper.getConfigValue(info.plugin, 
CFG_SKIP_ADD_JAR_TO_TEST_FEATURE, "true"));
         } else {
-            inlineCfgName = CFG_FEATURE_INLINED;
-            fileCfgName = CFG_TEST_FEATURE_FILE;
-            defaultFile = DEFAULT_FEATURE_FILE;
+            featuresDirCfgName = CFG_FEATURES;
+            defaultDir = DEFAULT_FEATURE_DIR;
             this.scope = Artifact.SCOPE_PROVIDED;
             skipAddDepCfgName = CFG_SKIP_ADD_FEATURE_DEPENDENCIES;
             defaultSkipValue = "false";
             this.name = "feature";
             this.skipAddJar = 
"true".equals(ProjectHelper.getConfigValue(info.plugin, 
CFG_SKIP_ADD_JAR_TO_FEATURE, "true"));
         }
-        this.inlinedFeature = ProjectHelper.getConfigValue(info.plugin, 
inlineCfgName, null);
-        this.featureFileName = ProjectHelper.getConfigValue(info.plugin, 
fileCfgName, defaultFile);
+        this.featuresDirName = ProjectHelper.getConfigValue(info.plugin, 
featuresDirCfgName, defaultDir);
         final String skipCfg = ProjectHelper.getConfigValue(info.plugin, 
skipAddDepCfgName, defaultSkipValue);
         this.skipAddDep = "true".equals(skipCfg.toLowerCase());
-        this.jarStartLevel = ProjectHelper.getConfigValue(info.plugin, 
CFG_JAR_START_LEVEL, DEFAULT_START_LEVEL);
+        this.jarStartOrder = ProjectHelper.getConfigValue(info.plugin, 
CFG_JAR_START_ORDER, null);
     }
 
     public String getName() {
         return this.name;
     }
 
-    public String getInlinedFeature() {
-        return this.inlinedFeature;
-    }
-
-    public String getFeatureFileName() {
-        return this.featureFileName;
+    public String getFeaturesDir() {
+        return this.featuresDirName;
     }
 
     public boolean isSkipAddDependencies() {
@@ -125,14 +110,12 @@ public class FeatureProjectConfig {
         return this.isTest;
     }
 
-    public String getJarStartLevel() {
-        return this.jarStartLevel;
+    public String getJarStartOrder() {
+        return this.jarStartOrder;
     }
 
     public boolean isSkipAddJarToFeature() {
         return this.skipAddJar;
     }
-
-
 }
 
diff --git 
a/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java 
b/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
index b0f379b..cc46a49 100644
--- a/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
@@ -16,17 +16,24 @@
  */
 package org.apache.sling.feature.maven;
 
+import java.util.List;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
 import org.apache.sling.feature.Feature;
 
-public class FeatureProjectInfo extends ProjectInfo {
+public class FeatureProjectInfo {
+
+    public MavenProject project;
+    public Plugin       plugin;
 
     public boolean featureDone = false;
     public boolean testFeatureDone = false;
 
-    public Feature feature;
-    public Feature assembledFeature;
+    public List<Feature> features;
+    public List<Feature> assembledFeatures;
 
-    public Feature testFeature;
-    public Feature assembledTestFeature;
+    public List<Feature> testFeatures;
+    public List<Feature> assembledTestFeatures;
 }
 
diff --git a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java 
b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
index c568cae..d952d25 100644
--- a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
+++ b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
@@ -16,6 +16,16 @@
  */
 package org.apache.sling.feature.maven;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
 import org.apache.sling.feature.Artifact;
@@ -29,15 +39,6 @@ import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.codehaus.plexus.logging.Logger;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
 /**
  * The processor processes all feature projects.
  */
@@ -48,28 +49,20 @@ public class Preprocessor {
      * @param env The environment with all maven settings and projects
      */
     public void process(final Environment env) {
-        for(final ProjectInfo info : env.modelProjects.values()) {
-            if ( info instanceof FeatureProjectInfo ) {
-                final FeatureProjectInfo finfo = (FeatureProjectInfo)info;
-                process(env, finfo, FeatureProjectConfig.getMainConfig(finfo));
-                process(env, finfo, FeatureProjectConfig.getTestConfig(finfo));
-                if ( 
FeatureConstants.PACKAGING_FEATURE.equals(info.project.getPackaging()) && 
finfo.feature == null ) {
-                    throw new RuntimeException("Feature project has no feature 
defined: " + info.project.getId());
-                }
-
-                ProjectHelper.storeProjectInfo(finfo);
-            } else {
-                final ApplicationProjectInfo ainfo = 
(ApplicationProjectInfo)info;
-                process(env, ainfo, 
ApplicationProjectConfig.getMainConfig(ainfo));
-                process(env, ainfo, 
ApplicationProjectConfig.getTestConfig(ainfo));
-
-                ProjectHelper.storeProjectInfo(ainfo);
+        for(final FeatureProjectInfo finfo : env.modelProjects.values()) {
+            process(env, finfo, FeatureProjectConfig.getMainConfig(finfo));
+            process(env, finfo, FeatureProjectConfig.getTestConfig(finfo));
+            if ( 
FeatureConstants.PACKAGING_FEATURE.equals(finfo.project.getPackaging()) && 
finfo.features.isEmpty() ) {
+                throw new RuntimeException("Feature project has no feature 
defined: " + finfo.project.getId());
             }
+
+            ProjectHelper.storeProjectInfo(finfo);
         }
     }
 
     /**
-     * Process a single feature project.
+     * Process a feature project.
+     * This method is invoked twice, once for the main project and one for 
testing.
      *
      * @param env The environment with all maven settings and projects
      * @param info The project to process.
@@ -83,6 +76,7 @@ public class Preprocessor {
             env.logger.debug("Return assembled " + config.getName() + " for " 
+ info.project.getId());
             return;
         }
+
         // prevent recursion and multiple processing
         if ( config.isTestConfig() ) {
             info.testFeatureDone = true;
@@ -91,16 +85,16 @@ public class Preprocessor {
         }
         env.logger.debug("Processing " + config.getName() + " in project " + 
info.project.getId());
 
-        // read project feature, either inlined or from file
-        final Feature feature = readProjectFeature(env.logger, info.project, 
config);
-        if ( feature == null ) {
-            env.logger.debug("No " + config.getName() + " found in project " + 
info.project.getId());
-            return;
-        }
+        // read project features
+        final List<Feature> features = readProjectFeatures(env.logger, 
info.project, config);
         if ( config.isTestConfig() ) {
-            info.testFeature = feature;
+            info.testFeatures = features;
         } else {
-            info.feature = feature;
+            info.features = features;
+        }
+        if ( features.isEmpty() ) {
+            env.logger.debug("No " + config.getName() + " found in project " + 
info.project.getId());
+            return;
         }
 
         // process attachments (only for jar or bundle)
@@ -109,40 +103,52 @@ public class Preprocessor {
             if ( config.isSkipAddJarToFeature() ) {
                 env.logger.debug("Skip adding jar to " + config.getName());
             } else {
+                if ( info.features.size() > 1 ) {
+                    throw new RuntimeException("Jar can only be added if just 
one feature is defined in the project");
+                }
                 final Artifact jar = new Artifact(new 
ArtifactId(info.project.getGroupId(),
                         info.project.getArtifactId(),
                         info.project.getVersion(),
                         null,
                         "jar"));
-                jar.getMetadata().put(Artifact.KEY_START_ORDER, 
String.valueOf(config.getJarStartLevel()));
-                feature.getBundles().add(jar);
+                if ( config.getJarStartOrder() != null ) {
+                    
jar.setStartOrder(Integer.valueOf(config.getJarStartOrder()));
+                }
+                features.get(0).getBundles().add(jar);
             }
         }
 
-        final Feature assembledFeature = FeatureBuilder.assemble(feature, new 
BuilderContext(this.createFeatureProvider(env,
+        // assemble features
+        final List<Feature> assembledFeatures = new ArrayList<>();
+        for(final Feature f : (config.isTestConfig() ? info.testFeatures : 
info.features)) {
+            final Feature assembledFeature = FeatureBuilder.assemble(f, new 
BuilderContext(this.createFeatureProvider(env,
                 info,
                 config.isTestConfig(),
                 config.isSkipAddDependencies(),
                 config.getScope(), null)));
+            assembledFeatures.add(assembledFeature);
+        }
         if ( config.isTestConfig() ) {
-            info.assembledTestFeature = assembledFeature;
+            info.assembledTestFeatures = assembledFeatures;
         } else {
-            info.assembledFeature = assembledFeature;
+            info.assembledFeatures = assembledFeatures;
         }
 
         if ( config.isSkipAddDependencies() ) {
-            env.logger.debug("Not adding artifacts from feature as 
dependencies");
+            env.logger.debug("Not adding artifacts from features as 
dependencies");
         } else {
-            addDependenciesFromFeature(env, info, assembledFeature, 
config.getScope());
+            for(final Feature f : assembledFeatures) {
+                addDependenciesFromFeature(env, info, f, config.getScope());
+            }
         }
     }
 
-    private void scan(final List<File> files, final File dir, final String 
ext) {
+    private void scan(final List<File> files, final File dir) {
         for(final File f : dir.listFiles()) {
             if ( !f.getName().startsWith(".") ) {
                 if ( f.isDirectory() ) {
-                    scan(files, f, ext);
-                } else if ( f.getName().endsWith("." + ext) ) {
+                    scan(files, f);
+                } else if ( f.getName().endsWith(".json") ) {
                     files.add(f);
                 }
             }
@@ -150,139 +156,6 @@ public class Preprocessor {
     }
 
     /**
-     * Process a single application project.
-     *
-     * @param env The environment with all maven settings and projects
-     * @param info The project to process.
-     * @param config The configuration for the project.
-     */
-    private void process(final Environment env,
-            final ApplicationProjectInfo info,
-            final ApplicationProjectConfig config) {
-        final List<Feature> featureList = new ArrayList<>();
-        env.logger.debug("Processing " + config.getName() + " in project " + 
info.project.getId());
-
-        // an application supports two sets of files:
-        // features and references to features
-
-        // feature files first:
-        final File dir = new File(info.project.getBasedir(), 
config.getFeatureDir());
-        if ( dir.exists() ) {
-            final List<File> files = new ArrayList<>();
-            scan(files, dir, "json");
-
-            for(final File file : files) {
-                // create id in case the file does not contain one
-                // classifier is the hard part, we use the file path/name
-                String fileName = 
file.getAbsolutePath().substring(dir.getAbsolutePath().length() + 1);
-                fileName = fileName.substring(0, fileName.length() - 5); // 
remove .json
-                fileName = fileName.replace(File.separatorChar, '_');
-                fileName = fileName.replace('-', '_');
-                final String classifier;
-                if ( config.isTestConfig() ) {
-                    classifier = "test_" + fileName;
-                } else {
-                    classifier = fileName;
-                }
-                final ArtifactId id = new ArtifactId(info.project.getGroupId(),
-                        info.project.getArtifactId(),
-                        info.project.getVersion(),
-                        classifier,
-                        FeatureConstants.PACKAGING_FEATURE);
-
-                // We should pass in an "id" to FeatureJSONReader.read and 
later on check the id (again, need to handle ref files)
-                try (final FileReader reader = new FileReader(file)) {
-                    final Feature feature = FeatureJSONReader.read(reader, id, 
file.getAbsolutePath());
-
-                    this.checkFeatureId(id, feature);
-
-                    this.setProjectInfo(info.project, feature);
-                    this.postProcessReadFeature(feature);
-                    featureList.add(feature);
-
-                } catch ( final IOException io) {
-                    throw new RuntimeException("Unable to read feature " + 
file.getAbsolutePath(), io);
-                }
-            }
-        } else {
-            env.logger.debug("Feature directory " + config.getFeatureDir() + " 
does not exist in project " + info.project.getId());
-        }
-        final List<Feature> assembledFeatureList = new ArrayList<>();
-        for(final Feature feature : featureList) {
-            final Feature assembledFeature = FeatureBuilder.assemble(feature, 
new BuilderContext(this.createFeatureProvider(env,
-                    info,
-                    config.isTestConfig(),
-                    config.isSkipAddDependencies(),
-                    config.getScope(),
-                    featureList)));
-            assembledFeatureList.add(assembledFeature);
-        }
-        if ( config.isTestConfig() ) {
-            info.testFeatures = featureList;
-            info.assembledTestFeatures = assembledFeatureList;
-        } else {
-            info.features = featureList;
-            info.assembledFeatures = assembledFeatureList;
-        }
-
-        // and now references
-        final List<Feature> featureRefList = new ArrayList<>();
-        final File refDir = new File(info.project.getBasedir(), 
config.getFeatureRefDir());
-        if ( refDir.exists() ) {
-            final List<File> files = new ArrayList<>();
-            scan(files, refDir, "ref");
-
-            for(final File file : files) {
-                try {
-                    final List<String> features = 
org.apache.sling.feature.io.IOUtils.parseFeatureRefFile(file);
-                    if ( features.isEmpty() ) {
-                        env.logger.debug("Empty feature ref file at " + file);
-                    } else {
-                        for(final String ref : features) {
-                            if ( !ref.startsWith("mvn:") ) {
-                                throw new RuntimeException("Unsupported 
feature ref in feature ref file at " + file + " : " + ref);
-                            }
-                            final ArtifactId id = ArtifactId.fromMvnUrl(ref);
-                            final Feature feature = 
this.createFeatureProvider(env, info, config.isTestConfig(), 
config.isSkipAddDependencies(), config.getScope(), null).provide(id);
-                            if ( feature == null ) {
-                                throw new RuntimeException("Unable to resolve 
feature " + id);
-                            }
-                            featureRefList.add(feature);
-                        }
-                    }
-                } catch ( final IOException io) {
-                    throw new RuntimeException("Unable to read feature " + 
file.getAbsolutePath(), io);
-                }
-            }
-        }
-        final List<Feature> assembledFeatureRefList = new ArrayList<>();
-        for(final Feature feature : featureRefList) {
-            final Feature assembledFeature = FeatureBuilder.assemble(feature, 
new BuilderContext(this.createFeatureProvider(env,
-                    info,
-                    config.isTestConfig(),
-                    config.isSkipAddDependencies(),
-                    config.getScope(),
-                    featureList)));
-            assembledFeatureRefList.add(assembledFeature);
-        }
-        if ( config.isTestConfig() ) {
-            info.testFeatures.addAll(featureRefList);
-            info.assembledTestFeatures.addAll(assembledFeatureRefList);
-        } else {
-            info.features.addAll(featureRefList);
-            info.assembledFeatures.addAll(assembledFeatureRefList);
-        }
-
-        if ( config.isSkipAddDependencies() ) {
-            env.logger.debug("Not adding artifacts from features as 
dependencies");
-        } else {
-            for(final Feature feature : assembledFeatureList) {
-                addDependenciesFromFeature(env, info, feature, 
config.getScope());
-            }
-        }
-    }
-
-    /**
      * Add all dependencies from the feature
      * @param env The environment
      * @param info The project info
@@ -291,7 +164,7 @@ public class Preprocessor {
      */
     private void addDependenciesFromFeature(
             final Environment env,
-            final ProjectInfo info,
+            final FeatureProjectInfo info,
             final Feature assembledFeature,
             final String scope) {
         for(final org.apache.sling.feature.Artifact entry : 
assembledFeature.getBundles()) {
@@ -329,7 +202,7 @@ public class Preprocessor {
     }
 
     /**
-     * Read the feature for a feature project.
+     * Read the features for a feature project.
      * The feature is either inlined in the pom or stored in a file in the 
project.
      *
      * @param logger The logger
@@ -337,70 +210,63 @@ public class Preprocessor {
      * @param config The configuration
      * @return The feature or {@code null}
      */
-    protected Feature readProjectFeature(
+    protected List<Feature> readProjectFeatures(
             final Logger logger,
             final MavenProject project,
             final FeatureProjectConfig config) {
-        final File featureFile = new File(project.getBasedir(), 
config.getFeatureFileName());
-        logger.debug("Checking feature file " + config.getFeatureFileName() + 
" : " + featureFile.exists());
-        logger.debug("Inlined feature : " + (config.getInlinedFeature() != 
null));
+        // feature files first:
+        final File dir = new File(project.getBasedir(), 
config.getFeaturesDir());
+        if ( dir.exists() ) {
+            final List<Feature> featureList = new ArrayList<>();
+            final List<File> files = new ArrayList<>();
+            scan(files, dir);
 
-        if ( config.getInlinedFeature() != null && featureFile.exists() ) {
-            throw new RuntimeException("Only one (feature file or inlined 
feature) can be specified - but not both");
-        }
+            for(final File file : files) {
+                final StringBuilder sb = new StringBuilder();
+                try (final Reader reader = new FileReader(file)) {
+                    final char[] buf = new char[4096];
+                    int l = 0;
 
-        final String classifier;
-        if ( config.isTestConfig() ) {
-            classifier = FeatureConstants.CLASSIFIER_TEST_FEATURE;
-        } else if ( 
FeatureConstants.PACKAGING_FEATURE.equals(project.getPackaging()) ) {
-            classifier = null;
-        } else {
-            classifier = FeatureConstants.CLASSIFIER_FEATURE;
-        }
-        final ArtifactId id = new ArtifactId(project.getGroupId(),
-                project.getArtifactId(),
-                project.getVersion(),
-                classifier,
-                FeatureConstants.PACKAGING_FEATURE);
-
-        final Feature feature;
-        if ( config.getInlinedFeature() != null ) {
-            logger.debug("Reading inlined model from project " + 
project.getId());
-            try (final Reader reader = new 
StringReader(config.getInlinedFeature())) {
-                feature = FeatureJSONReader.read(reader, id, null);
-            } catch ( final IOException io) {
-                throw new RuntimeException("Unable to read inlined feature", 
io);
+                    while (( l = reader.read(buf)) > 0 ) {
+                        sb.append(buf, 0, l);
+                    }
+                } catch ( final IOException io) {
+                    throw new RuntimeException("Unable to read feature " + 
file.getAbsolutePath(), io);
+                }
+
+                final String json = Substitution.replaceMavenVars(project, 
sb.toString());
+
+                try (final Reader reader = new StringReader(json)) {
+                    final Feature feature = FeatureJSONReader.read(reader, 
file.getAbsolutePath());
+
+                    this.checkFeatureId(project, feature);
+
+                    this.setProjectInfo(project, feature);
+                    this.postProcessReadFeature(feature);
+                    featureList.add(feature);
+
+                } catch ( final IOException io) {
+                    throw new RuntimeException("Unable to read feature " + 
file.getAbsolutePath(), io);
+                }
             }
+
+            return featureList;
         } else {
-            if ( !featureFile.exists() ) {
-                logger.debug("Feature file " + featureFile + " in project " + 
project.getId() + " does not exist.");
-                return null;
-            }
-            logger.debug("Reading feature " + featureFile + " in project " + 
project.getId());
-            try (final FileReader reader = new FileReader(featureFile)) {
-                feature = FeatureJSONReader.read(reader, id, 
featureFile.getAbsolutePath());
-            } catch ( final IOException io) {
-                throw new RuntimeException("Unable to read feature " + 
featureFile, io);
-            }
+            logger.debug("Feature directory " + config.getFeaturesDir() + " 
does not exist in project " + project.getId());
+            return Collections.emptyList();
         }
-        this.checkFeatureId(id, feature);
-
-        this.setProjectInfo(project, feature);
-
-        // post process and return
-        return postProcessReadFeature(feature);
     }
 
-    private void checkFeatureId(final ArtifactId id, final Feature feature) {
+    private void checkFeatureId(final MavenProject project, final Feature 
feature) {
         // check feature id
-        if ( !id.getGroupId().equals(feature.getId().getGroupId()) ) {
-            throw new RuntimeException("Wrong group id for feature. It should 
be " + id.getGroupId() + " but is " + feature.getId().getGroupId());
+        if ( !project.getGroupId().equals(feature.getId().getGroupId()) ) {
+            throw new RuntimeException("Wrong group id for feature. It should 
be " + project.getGroupId() + " but is " + feature.getId().getGroupId());
         }
-        if ( !id.getArtifactId().equals(feature.getId().getArtifactId()) ) {
-            throw new RuntimeException("Wrong artifact id for feature. It 
should be " + id.getArtifactId() + " but is " + 
feature.getId().getArtifactId());
+        if ( !project.getArtifactId().equals(feature.getId().getArtifactId()) 
) {
+            throw new RuntimeException("Wrong artifact id for feature. It 
should be " + project.getArtifactId() + " but is " + 
feature.getId().getArtifactId());
         }
-        if ( !id.getVersion().equals(feature.getId().getVersion()) ) {
-            throw new RuntimeException("Wrong version for feature. It should 
be " + id.getVersion() + " but is " + feature.getId().getVersion());
+        if ( !project.getVersion().equals(feature.getId().getVersion()) ) {
+            throw new RuntimeException("Wrong version for feature. It should 
be " + project.getVersion() + " but is " + feature.getId().getVersion());
         }
     }
 
@@ -437,7 +303,7 @@ public class Preprocessor {
     }
 
     protected FeatureProvider createFeatureProvider(final Environment env,
-            final ProjectInfo info,
+            final FeatureProjectInfo info,
             final boolean isTest,
             final boolean skipAddDependencies,
             final String dependencyScope,
@@ -456,45 +322,30 @@ public class Preprocessor {
 
                 // if it's a project from the current reactor build, we can't 
resolve it right now
                 final String key = id.getGroupId() + ":" + id.getArtifactId();
-                final ProjectInfo depProjectInfo = env.modelProjects.get(key);
+                final FeatureProjectInfo depProjectInfo = 
env.modelProjects.get(key);
                 if ( depProjectInfo != null ) {
                     env.logger.debug("Found reactor " + id.getType() + " 
dependency to project: " + id);
                     // check if it is a feature project
-                    if ( depProjectInfo instanceof FeatureProjectInfo ) {
-                        final FeatureProjectInfo depInfo = 
(FeatureProjectInfo)depProjectInfo;
-                        if ( isTest ) {
-                            process(env, depInfo, 
FeatureProjectConfig.getTestConfig(depInfo));
-                        } else {
-                            process(env, depInfo, 
FeatureProjectConfig.getMainConfig(depInfo));
-                        }
-                        if ( isTest && depInfo.assembledTestFeature == null ) {
-                            env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive test feature dependency list including project " + 
info.project);
-                        } else if ( !isTest && depInfo.assembledFeature == 
null ) {
-                            env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive feature dependency list including project " + 
info.project);
-                        } else {
-
-                            if ( isTest ) {
-                                return depInfo.testFeature;
-                            } else {
-                                return depInfo.feature;
-                            }
-                        }
+                    final FeatureProjectInfo depInfo = depProjectInfo;
+                    if ( isTest ) {
+                        process(env, depInfo, 
FeatureProjectConfig.getTestConfig(depInfo));
                     } else {
-                        // we only support a dependency to *this* application 
project
-                        final ApplicationProjectInfo depInfo = 
(ApplicationProjectInfo)depProjectInfo;
-                        if ( depInfo != info) {
-                            env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Feature dependency is to a different application project 
from " + info.project);
-                            return null;
-                        }
-                        if ( projectFeatures != null ) {
-                            for(final Feature f : projectFeatures) {
-                                if ( f.getId().equals(id)) {
-                                    return f;
-                                }
-                            }
+                        process(env, depInfo, 
FeatureProjectConfig.getMainConfig(depInfo));
+                    }
+                    Feature found = null;
+                    for(final Feature f : (isTest ? 
depInfo.assembledTestFeatures : depInfo.assembledFeatures)) {
+                        if ( f.getId().equals(id) ) {
+                            found = f;
+                            break;
                         }
-                        return null;
                     }
+
+                    if ( isTest && found == null ) {
+                        env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive test feature dependency list including project " + 
info.project);
+                    } else if ( !isTest && found == null ) {
+                        env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive feature dependency list including project " + 
info.project);
+                    }
+                    return found;
                 } else {
                     env.logger.debug("Found external " + id.getType() + " 
dependency: " + id);
 
diff --git a/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java 
b/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
index d7c1a2b..debb910 100644
--- a/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
+++ b/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
@@ -16,6 +16,15 @@
  */
 package org.apache.sling.feature.maven;
 
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
@@ -34,14 +43,6 @@ import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 public abstract class ProjectHelper {
 
     /** Read feature. */
@@ -52,18 +53,6 @@ public abstract class ProjectHelper {
     private static final String ASSEMBLED_FEATURE_JSON = 
Feature.class.getName() + "/assembledmain.json";
     private static final String ASSEMBLED_TEST_FEATURE_JSON = 
Feature.class.getName() + "/assembledtest.json";
 
-    private static void store(final MavenProject project, final String key, 
final Feature feature) {
-        if ( feature != null ) {
-            // we have to serialize as the dependency lifecycle participant 
uses a different class loader (!)
-            try ( final StringWriter w1 = new StringWriter() ) {
-                FeatureJSONWriter.write(w1, feature);
-                project.setContextValue(key, w1.toString());
-            } catch ( final IOException ioe) {
-                throw new RuntimeException(ioe.getMessage(), ioe);
-            }
-        }
-    }
-
     private static void store(final MavenProject project, final String key, 
final List<Feature> features) {
         if ( features != null && !features.isEmpty()) {
             project.setContextValue(key, features.size());
@@ -81,30 +70,6 @@ public abstract class ProjectHelper {
         }
     }
 
-    private static Feature getFeature(final MavenProject project, final String 
key) {
-        final String cacheKey = key + "-cache";
-        Feature result = null;
-        try {
-            result = (Feature) project.getContextValue(cacheKey);
-        } catch ( final Exception e) {
-            // if we get a class cast exception, we read again
-        }
-        if ( result == null ) {
-            final String text = (String)project.getContextValue(key);
-            if ( text == null ) {
-                result = null;
-            } else {
-                try ( final StringReader r = new StringReader(text) ) {
-                    result = FeatureJSONReader.read(r, project.getId());
-                    project.setContextValue(cacheKey, result);
-                } catch ( final IOException ioe) {
-                    throw new RuntimeException(ioe.getMessage(), ioe);
-                }
-            }
-        }
-        return result;
-    }
-
     @SuppressWarnings("unchecked")
     private static List<Feature> getFeatures(final MavenProject project, final 
String key) {
         final String cacheKey = key + "-cache";
@@ -133,7 +98,7 @@ public abstract class ProjectHelper {
                 project.setContextValue(cacheKey, result);
             }
         }
-        return result;
+        return result != null ? result : Collections.emptyList();
     }
 
     /**
@@ -142,54 +107,6 @@ public abstract class ProjectHelper {
      * @param info The project info
      */
     public static void storeProjectInfo(final FeatureProjectInfo info) {
-        store(info.project, RAW_FEATURE_JSON, info.feature);
-        store(info.project, RAW_TEST_FEATURE_JSON, info.testFeature);
-        store(info.project, ASSEMBLED_FEATURE_JSON, info.assembledFeature);
-        store(info.project, ASSEMBLED_TEST_FEATURE_JSON, 
info.assembledTestFeature);
-    }
-
-    /**
-     * Get the assembled feature from the project
-     * @param project The maven projet
-     * @return The assembled feature or {@code null}
-     */
-    public static Feature getAssembledFeature(final MavenProject project) {
-        return getFeature(project, ASSEMBLED_FEATURE_JSON);
-    }
-
-    /**
-     * Get the raw feature from the project
-     * @param project The maven projet
-     * @return The raw feature or {@code null}
-     */
-    public static Feature getFeature(final MavenProject project) {
-        return getFeature(project, RAW_FEATURE_JSON);
-    }
-
-    /**
-     * Get the assembled test feature from the project
-     * @param project The maven projet
-     * @return The assembled feature or {@code null}
-     */
-    public static Feature getAssembledTestFeature(final MavenProject project) {
-        return getFeature(project, ASSEMBLED_TEST_FEATURE_JSON);
-    }
-
-    /**
-     * Get the raw test feature from the project
-     * @param project The maven projet
-     * @return The raw feature or {@code null}
-     */
-    public static Feature getTestFeature(final MavenProject project) {
-        return getFeature(project, RAW_TEST_FEATURE_JSON);
-    }
-
-    /**
-     * Store all relevant information about the project for plugins to be
-     * retrieved
-     * @param info The project info
-     */
-    public static void storeProjectInfo(final ApplicationProjectInfo info) {
         store(info.project, RAW_FEATURE_JSON, info.features);
         store(info.project, RAW_TEST_FEATURE_JSON, info.testFeatures);
         store(info.project, ASSEMBLED_FEATURE_JSON, info.assembledFeatures);
diff --git a/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java 
b/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java
deleted file mode 100644
index 6e3fa0d..0000000
--- a/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.feature.maven;
-
-import org.apache.maven.model.Plugin;
-import org.apache.maven.project.MavenProject;
-
-public class ProjectInfo {
-
-    public MavenProject project;
-    public Plugin       plugin;
-}
-
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/Substitution.java 
b/src/main/java/org/apache/sling/feature/maven/Substitution.java
similarity index 63%
rename from src/main/java/org/apache/sling/feature/maven/mojos/Substitution.java
rename to src/main/java/org/apache/sling/feature/maven/Substitution.java
index a9a0ef2..5c46b52 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/Substitution.java
+++ b/src/main/java/org/apache/sling/feature/maven/Substitution.java
@@ -14,35 +14,14 @@
  * License for the specific language governing permissions and limitations 
under
  * the License.
  */
-package org.apache.sling.feature.maven.mojos;
+package org.apache.sling.feature.maven;
 
-import org.apache.maven.project.MavenProject;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Files;
 import java.util.Properties;
 
-class Substitution {
-    static File substituteMavenVars(MavenProject project, File f, File 
processedFeaturesDir) throws IOException {
-        File file = new File(processedFeaturesDir, f.getName());
-
-        if (file.exists() && file.lastModified() > f.lastModified()) {
-            // The file already exists, so we don't need to write it again
-            return file;
-        }
-
-        try (FileWriter fw = new FileWriter(file)) {
-            for (String s : Files.readAllLines(f.toPath())) {
-                fw.write(replaceMavenVars(project, s));
-                fw.write(System.getProperty("line.separator"));
-            }
-        }
-        return file;
-    }
+import org.apache.maven.project.MavenProject;
 
-    static String replaceMavenVars(MavenProject project, String s) {
+public class Substitution {
+    public static String replaceMavenVars(MavenProject project, String s) {
         // There must be a better way than enumerating all these?
         s = replaceAll(s, "project.groupId", project.getGroupId());
         s = replaceAll(s, "project.artifactId", project.getArtifactId());
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java
index 13912b3..04ef151 100644
--- 
a/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java
+++ 
b/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import java.io.File;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugins.annotations.Component;
@@ -24,42 +26,24 @@ import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
 import org.apache.sling.feature.maven.FeatureProjectConfig;
 
-import java.io.File;
-
 /**
  * Base class for all mojos.
  */
 public abstract class AbstractFeatureMojo extends AbstractMojo {
 
     /**
-     * The feature file..
-     * This parameter is evaluated in the {@link 
DependencyLifecycleParticipant}.
-     */
-    @Parameter(name = FeatureProjectConfig.CFG_FEATURE_FILE,
-            defaultValue="${basedir}/" + 
FeatureProjectConfig.DEFAULT_FEATURE_FILE)
-    private File featureFile;
-
-    /**
-     * The test feature file..
-     * This parameter is evaluated in the {@link 
DependencyLifecycleParticipant}.
-     */
-    @Parameter(name = FeatureProjectConfig.CFG_TEST_FEATURE_FILE,
-            defaultValue="${basedir}/" + 
FeatureProjectConfig.DEFAULT_TEST_FEATURE_FILE)
-    private File testFeatureFile;
-
-    /**
-     * Inlined model.
+     * Directory containing feature files
      * This parameter is evaluated in the {@link 
DependencyLifecycleParticipant}.
      */
-    @Parameter(name = FeatureProjectConfig.CFG_FEATURE_INLINED)
-    private String feature;
+    @Parameter(name = FeatureProjectConfig.CFG_FEATURES)
+    private String features;
 
     /**
-     * Inlined test model.
+     * Directory containing test feature files
      * This parameter is evaluated in the {@link 
DependencyLifecycleParticipant}.
      */
-    @Parameter(name = FeatureProjectConfig.CFG_TEST_FEATURE_INLINED)
-    private String testFeature;
+    @Parameter(name = FeatureProjectConfig.CFG_TEST_FEATURES)
+    private String testFeatures;
 
     /**
      * If set to {@code true} the artifacts from the feature are not as 
dependencies to the project.
@@ -97,9 +81,8 @@ public abstract class AbstractFeatureMojo extends 
AbstractMojo {
      * The start level for the attached jar/bundle.
      * This parameter is evaluated in the {@link 
DependencyLifecycleParticipant}.
      */
-    @Parameter(name=FeatureProjectConfig.CFG_JAR_START_LEVEL,
-            defaultValue=FeatureProjectConfig.DEFAULT_START_LEVEL)
-    private int jarStartLevel;
+    @Parameter(name=FeatureProjectConfig.CFG_JAR_START_ORDER)
+    private int jarStartOrder;
 
     @Parameter(property = "project", readonly = true, required = true)
     protected MavenProject project;
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
index e97a3d1..aeaf4ec 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
@@ -16,6 +16,23 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
@@ -38,23 +55,7 @@ import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
 import org.apache.sling.feature.maven.FeatureConstants;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.stream.StreamSupport;
+import org.apache.sling.feature.maven.Substitution;
 
 /**
  * Aggregate multiple features into a single one.
@@ -89,9 +90,11 @@ public class AggregateFeatures extends AbstractFeatureMojo {
     @Component
     ArtifactResolver artifactResolver;
 
+    public static final String FEATURE_PROCESSED_LOCATION = 
"/features/processed";
+
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
-        File aggregatedFeaturesDir = new 
File(project.getBuild().getDirectory(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION);
+        File aggregatedFeaturesDir = new 
File(project.getBuild().getDirectory(), FEATURE_PROCESSED_LOCATION);
         aggregatedFeaturesDir.mkdirs();
         Map<ArtifactId, Feature> contextFeatures = 
readFeaturesFromDirectory(aggregatedFeaturesDir);
 
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeatures.java
similarity index 58%
rename from 
src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java
rename to src/main/java/org/apache/sling/feature/maven/mojos/AttachFeatures.java
index 2b045b3..fdbe00b 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeatures.java
@@ -16,24 +16,22 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
 import org.apache.sling.feature.maven.FeatureConstants;
 import org.apache.sling.feature.maven.ProjectHelper;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-
 /**
  * Attach the feature as a project artifact.
  */
@@ -42,16 +40,15 @@ import java.io.Writer;
       requiresDependencyResolution = ResolutionScope.TEST,
       threadSafe = true
     )
-public class AttachFeature extends AbstractFeatureMojo {
+public class AttachFeatures extends AbstractFeatureMojo {
 
     private void attach(final Feature feature,
-            final String artifactName,
             final String classifier)
     throws MojoExecutionException {
         if ( feature != null ) {
 
             // write the feature
-            final File outputFile = new 
File(this.project.getBuild().getDirectory() + File.separatorChar + 
artifactName);
+            final File outputFile = new 
File(this.project.getBuild().getDirectory() + File.separatorChar + classifier + 
".json");
             outputFile.getParentFile().mkdirs();
 
             try ( final Writer writer = new FileWriter(outputFile)) {
@@ -65,7 +62,6 @@ public class AttachFeature extends AbstractFeatureMojo {
                  && (FeatureConstants.CLASSIFIER_FEATURE.equals(classifier))) {
                 project.getArtifact().setFile(outputFile);
             } else {
-                // TODO do we need to check that the feature's GAV matches the 
project's GAV?
 
                 // otherwise attach it as an additional artifact
                 projectHelper.attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE,
@@ -76,43 +72,37 @@ public class AttachFeature extends AbstractFeatureMojo {
 
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
-        attach(ProjectHelper.getFeature(this.project), 
FeatureConstants.FEATURE_ARTIFACT_NAME, FeatureConstants.CLASSIFIER_FEATURE);
-        attach(ProjectHelper.getTestFeature(this.project), 
FeatureConstants.TEST_FEATURE_ARTIFACT_NAME, 
FeatureConstants.CLASSIFIER_TEST_FEATURE);
+        final Feature main = 
this.attachClassifierFeatures(ProjectHelper.getFeatures(this.project));
+        if ( main != null ) {
+            attach(main, FeatureConstants.CLASSIFIER_FEATURE);
+        }
 
-        attachClassifierFeatures();
+        final Feature test = 
this.attachClassifierFeatures(ProjectHelper.getTestFeatures(this.project));
+        if ( test != null ) {
+            attach(test, FeatureConstants.CLASSIFIER_TEST_FEATURE);
+        }
     }
 
-    void attachClassifierFeatures() throws MojoExecutionException {
+    /**
+     * Attach classifier features and return the main non classifier feature
+     * @return
+     * @throws MojoExecutionException
+     */
+    Feature attachClassifierFeatures(final List<Feature> features) throws 
MojoExecutionException {
         // Find all features that have a classifier and attach each of them
-        String processedFeatures = project.getBuild().getDirectory() + 
FeatureConstants.FEATURE_PROCESSED_LOCATION;
-
-        File featuresDir = new File(processedFeatures);
-        if (!featuresDir.isDirectory()) {
-            featuresDir = new File(project.getBasedir(), "src/main/features");
-            if (!featuresDir.isDirectory()) {
-                return;
-            }
-        }
-        for (File f : featuresDir.listFiles((d,f) -> f.endsWith(".json"))) {
-            try {
-                Feature feat = FeatureJSONReader.read(new FileReader(f), null);
-
-                ArtifactId aid = feat.getId();
-                // Only attach features that have the same GAV, they will 
differ in classifier
-                if (!aid.getGroupId().equals(project.getGroupId()))
-                    continue;
-                if (!aid.getArtifactId().equals(project.getArtifactId()))
-                    continue;
-                if (!aid.getVersion().equals(project.getVersion()))
-                    continue;
-
-                String classifier = aid.getClassifier();
-                if (classifier == null || classifier.length() == 0)
-                    continue;
-                projectHelper.attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE, classifier, f);
-            } catch (IOException e) {
-                throw new MojoExecutionException("Unable to attach embedded 
features", e);
+        Feature main = null;
+        for (final Feature f : features) {
+            if (f.getId().getClassifier() == null ) {
+                if ( main == null ) {
+                    main = f;
+                } else {
+                    // TODO we should check this already in the Preprocessor
+                    throw new MojoExecutionException("Project has more than 
one feature without a classifier.");
+                }
+            } else {
+                attach(f, f.getId().getClassifier());
             }
         }
+        return main;
     }
 }
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
 
b/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
index 7b23920..3ca6dc0 100644
--- 
a/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
+++ 
b/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
@@ -23,12 +23,9 @@ import org.apache.maven.artifact.resolver.ArtifactResolver;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.project.MavenProject;
-import org.apache.sling.feature.maven.ApplicationProjectInfo;
 import org.apache.sling.feature.maven.Environment;
-import org.apache.sling.feature.maven.FeatureConstants;
 import org.apache.sling.feature.maven.FeatureProjectInfo;
 import org.apache.sling.feature.maven.Preprocessor;
-import org.apache.sling.feature.maven.ProjectInfo;
 import org.codehaus.plexus.component.annotations.Component;
 import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.Logger;
@@ -72,12 +69,7 @@ public class DependencyLifecycleParticipant extends 
AbstractMavenLifecyclePartic
             Plugin plugin = project.getPlugin(PLUGIN_ID);
             if (plugin != null) {
                 logger.debug("Found project " + project.getId() + " using " + 
PLUGIN_ID);
-                final ProjectInfo info;
-                if ( 
FeatureConstants.PACKAGING_APPLICATION.equals(project.getPackaging()) ) {
-                    info = new ApplicationProjectInfo();
-                } else {
-                    info = new FeatureProjectInfo();
-                }
+                final FeatureProjectInfo info = new FeatureProjectInfo();
                 info.plugin = plugin;
                 info.project = project;
                 env.modelProjects.put(project.getGroupId() + ":" + 
project.getArtifactId(), info);
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/GenerateResources.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/GenerateResources.java
deleted file mode 100644
index 0fe467b..0000000
--- a/src/main/java/org/apache/sling/feature/maven/mojos/GenerateResources.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.feature.maven.mojos;
-
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.plugins.annotations.ResolutionScope;
-import org.apache.sling.feature.maven.FeatureConstants;
-
-import java.io.File;
-import java.io.IOException;
-
-@Mojo(
-        name = "generate-resources",
-        defaultPhase = LifecyclePhase.GENERATE_RESOURCES,
-        requiresDependencyResolution = ResolutionScope.TEST,
-        threadSafe = true)
-public class GenerateResources extends AbstractFeatureMojo {
-    @Parameter(defaultValue="${basedir}/src/main/features")
-    private File featuresDirectory;
-
-    @Override
-    public void execute() throws MojoExecutionException, MojoFailureException {
-        File[] files = featuresDirectory.listFiles();
-        if (files == null)
-            return;
-
-        File processedFeaturesDir = new 
File(project.getBuild().getDirectory(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION);
-        processedFeaturesDir.mkdirs();
-
-        for (File f : files) {
-            if (!f.getName().endsWith(".json")) {
-                continue;
-            }
-
-            try {
-                Substitution.substituteMavenVars(project, f, 
processedFeaturesDir);
-            } catch (IOException e) {
-                throw new MojoExecutionException("Problem processing feature 
file " + f.getAbsolutePath(), e);
-            }
-        }
-    }
-}
diff --git a/src/main/resources/META-INF/plexus/components.xml 
b/src/main/resources/META-INF/plexus/components.xml
index 8fc0c4f..4a0e114 100644
--- a/src/main/resources/META-INF/plexus/components.xml
+++ b/src/main/resources/META-INF/plexus/components.xml
@@ -27,7 +27,7 @@
           <lifecycle>
             <id>default</id>
             <phases>
-              
<package>org.apache.sling:slingstart-maven-plugin:attach-slingfeature</package>
+              
<package>org.apache.sling:slingfeature-maven-plugin:attach-features</package>
               
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
               
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
             </phases>
@@ -36,63 +36,6 @@
       </configuration>
     </component>
     <component>
-      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
-      <role-hint>osgifeature</role-hint>
-      
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
-      <configuration>
-        <lifecycles>
-          <lifecycle>
-            <id>default</id>
-            <phases>
-              
<package>org.apache.sling:slingstart-maven-plugin:attach-slingfeature</package>
-              
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
-              
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
-            </phases>
-          </lifecycle>
-        </lifecycles>
-      </configuration>
-    </component>
-    <component>
-      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
-      <role-hint>osgiapp</role-hint>
-      
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
-      <configuration>
-        <lifecycles>
-          <lifecycle>
-            <id>default</id>
-            <phases>
-              
<process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
-              
<compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
-              <process-test-resources>
-                  
org.apache.maven.plugins:maven-resources-plugin:testResources,
-              </process-test-resources>
-              
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
-              <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
-              
<prepare-package>org.apache.sling:slingstart-maven-plugin:prepare-package</prepare-package>
              
-              <package>
-                  org.apache.sling:slingstart-maven-plugin:attach-slingfeature,
-                  org.apache.sling:slingstart-maven-plugin:package
-              </package>
-              
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
-              
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
-            </phases>
-          </lifecycle>
-        </lifecycles>
-      </configuration>
-    </component>
-    <component>
-      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
-      <role-hint>osgifeature</role-hint>
-      
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
-      <configuration>
-        <type>osgifeature</type>
-        <includesDependencies>false</includesDependencies>
-        <language>json</language>
-        <extension>json</extension>
-        <addedToClasspath>false</addedToClasspath>
-      </configuration>
-    </component>
-    <component>
       <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
       <role-hint>slingfeature</role-hint>
       
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
@@ -104,29 +47,5 @@
         <addedToClasspath>false</addedToClasspath>
       </configuration>
     </component>
-    <component>
-      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
-      <role-hint>osgiapp</role-hint>
-      
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
-      <configuration>
-        <type>osgiapp</type>
-        <includesDependencies>false</includesDependencies>
-        <language>java</language>
-        <extension>jar</extension>
-        <addedToClasspath>false</addedToClasspath>
-      </configuration>
-    </component>
-    <component>
-      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
-      <role-hint>osgijar</role-hint>
-      
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
-      <configuration>
-        <type>osgijar</type>
-        <includesDependencies>false</includesDependencies>
-        <language>java</language>
-        <extension>zip</extension>
-        <addedToClasspath>false</addedToClasspath>
-      </configuration>
-    </component>
   </components>
 </component-set>
diff --git 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
index 72e9523..f003e42 100644
--- 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
+++ 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
@@ -16,6 +16,27 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
@@ -28,7 +49,6 @@ import org.apache.maven.repository.RepositorySystem;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
-import org.apache.sling.feature.maven.FeatureConstants;
 import org.apache.sling.feature.maven.mojos.AggregateFeatures.FeatureConfig;
 import org.junit.After;
 import org.junit.Before;
@@ -37,27 +57,6 @@ import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.Reader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 public class AggregateFeaturesTest {
     private Path tempDir;
     private static Map<String, ArtifactId> pluginCallbacks;
@@ -139,7 +138,7 @@ public class AggregateFeaturesTest {
 
         af.execute();
 
-        File expectedFile = new File(tempDir.toFile(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION + "/aggregated.json");
+        File expectedFile = new File(tempDir.toFile(), 
AggregateFeatures.FEATURE_PROCESSED_LOCATION + "/aggregated.json");
         try (Reader fr = new FileReader(expectedFile)) {
             Feature genFeat = FeatureJSONReader.read(fr, null);
             ArtifactId id = genFeat.getId();
@@ -205,7 +204,7 @@ public class AggregateFeaturesTest {
 
         af.execute();
 
-        File expectedFile = new File(tempDir.toFile(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION + "/aggregated.json");
+        File expectedFile = new File(tempDir.toFile(), 
AggregateFeatures.FEATURE_PROCESSED_LOCATION + "/aggregated.json");
         try (Reader fr = new FileReader(expectedFile)) {
             Feature genFeat = FeatureJSONReader.read(fr, null);
             ArtifactId id = genFeat.getId();
@@ -339,7 +338,7 @@ public class AggregateFeaturesTest {
 
         af.execute();
 
-        File expectedFile = new File(tempDir.toFile(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION + "/agg.json");
+        File expectedFile = new File(tempDir.toFile(), 
AggregateFeatures.FEATURE_PROCESSED_LOCATION + "/agg.json");
         try (Reader fr = new FileReader(expectedFile)) {
             Feature genFeat = FeatureJSONReader.read(fr, null);
             ArtifactId id = genFeat.getId();
@@ -422,7 +421,7 @@ public class AggregateFeaturesTest {
 
         af.execute();
 
-        File expectedFile = new File(tempDir.toFile(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION + "/mynewfeature.json");
+        File expectedFile = new File(tempDir.toFile(), 
AggregateFeatures.FEATURE_PROCESSED_LOCATION + "/mynewfeature.json");
         try (Reader fr = new FileReader(expectedFile)) {
             Feature genFeat = FeatureJSONReader.read(fr, null);
             ArtifactId id = genFeat.getId();
diff --git 
a/src/test/java/org/apache/sling/feature/maven/mojos/AttachFeatureTest.java 
b/src/test/java/org/apache/sling/feature/maven/mojos/AttachFeatureTest.java
index 949e945..0b9e1d1 100644
--- a/src/test/java/org/apache/sling/feature/maven/mojos/AttachFeatureTest.java
+++ b/src/test/java/org/apache/sling/feature/maven/mojos/AttachFeatureTest.java
@@ -16,20 +16,34 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.maven.model.Build;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.apache.sling.feature.maven.FeatureConstants;
 import org.junit.Test;
 import org.mockito.Mockito;
 
-import java.io.File;
-
 public class AttachFeatureTest {
     @Test
     public void testAttachArtifacts() throws Exception {
         File feat_a = new 
File(getClass().getResource("/attach-resources/features/processed/test_a.json").toURI());
         File feat_d = new 
File(getClass().getResource("/attach-resources/features/processed/test_d.json").toURI());
+
+        final List<Feature> features = new ArrayList<>();
+        try ( final FileReader r = new FileReader(feat_a) ) {
+            features.add(FeatureJSONReader.read(r, feat_a.getAbsolutePath()));
+        }
+        try ( final FileReader r = new FileReader(feat_d) ) {
+            features.add(FeatureJSONReader.read(r, feat_d.getAbsolutePath()));
+        }
+
         File featuresDir = 
feat_a.getParentFile().getParentFile().getParentFile();
 
         Build build = new Build();
@@ -41,15 +55,15 @@ public class AttachFeatureTest {
         project.setVersion("1.0.1");
         project.setBuild(build);
 
-        AttachFeature af = new AttachFeature();
+        AttachFeatures af = new AttachFeatures();
         af.project = project;
 
         MavenProjectHelper helper = Mockito.mock(MavenProjectHelper.class);
         af.projectHelper = helper;
 
-        af.attachClassifierFeatures();
-        Mockito.verify(helper).attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE, "testa", feat_a);
-        Mockito.verify(helper).attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE, "testd", feat_d);
+        af.attachClassifierFeatures(features);
+        Mockito.verify(helper).attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE, "testa", new File(featuresDir, 
"testa.json"));
+        Mockito.verify(helper).attachArtifact(project, 
FeatureConstants.PACKAGING_FEATURE, "testd", new File(featuresDir, 
"testd.json"));
         Mockito.verifyNoMoreInteractions(helper);
     }
 }
diff --git 
a/src/test/java/org/apache/sling/feature/maven/mojos/GenerateResourceTest.java 
b/src/test/java/org/apache/sling/feature/maven/mojos/GenerateResourceTest.java
deleted file mode 100644
index 1cfa1ba..0000000
--- 
a/src/test/java/org/apache/sling/feature/maven/mojos/GenerateResourceTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.feature.maven.mojos;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.project.MavenProject;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Comparator;
-import java.util.Properties;
-
-import static org.junit.Assert.assertEquals;
-
-public class GenerateResourceTest {
-    @Test
-    public void testExecute() throws Exception {
-        File srcDir = new 
File(getClass().getResource("/generate-resources/test1.json").toURI()).getParentFile();
-
-        Build build = new Build();
-
-        MavenProject project = new MavenProject();
-        project.setBuild(build);
-        project.setGroupId("gid");
-        project.setArtifactId("aid");
-        project.setVersion("1.2.3-SNAPSHOT");
-
-        GenerateResources gr = new GenerateResources();
-        setPrivateField(gr, "featuresDirectory", srcDir);
-        setPrivateField(gr, "project", project);
-
-        Path tempDir = Files.createTempDirectory("grtest");
-        build.setDirectory(tempDir.toString());
-
-        gr.execute();
-
-        try {
-            File[] files = new File(tempDir.toFile(), "features/processed")
-                    .listFiles((d, n) -> n.endsWith(".json"));
-            assertEquals(1, files.length);
-            byte[] bytes = Files.readAllBytes(files[0].toPath());
-            String s = new String(bytes).trim();
-            assertEquals("\"---gid---aid---aid---1.2.3-SNAPSHOT---\"", s);
-        } finally {
-            Files.walk(tempDir)
-            .sorted(Comparator.reverseOrder())
-            .map(Path::toFile)
-            .forEach(File::delete);
-        }
-    }
-
-    @Test
-    public void testExecuteWithoutFeatureFiles() throws Exception {
-        GenerateResources gr = new GenerateResources();
-        setPrivateField(gr, "featuresDirectory", new File("nonexistent"));
-
-        // Should return gracefully
-        gr.execute();
-    }
-
-    @Test
-    public void testReplaceVars() {
-        MavenProject mp = Mockito.mock(MavenProject.class);
-
-        Properties props = new Properties();
-        props.put("foo", "bar");
-
-        Mockito.when(mp.getGroupId()).thenReturn("abc");
-        Mockito.when(mp.getArtifactId()).thenReturn("a.b.c");
-        Mockito.when(mp.getVersion()).thenReturn("1.2.3-SNAPSHOT");
-        Mockito.when(mp.getProperties()).thenReturn(props);
-
-        assertEquals("xxxabcyyy", Substitution.replaceMavenVars(mp,
-                "xxx${project.groupId}yyy"));
-        assertEquals("xxxabcyyya.b.c1.2.3-SNAPSHOT", 
Substitution.replaceMavenVars(mp,
-                
"xxx${project.groupId}yyy${project.artifactId}${project.version}"));
-        assertEquals("xxxbaryyy", Substitution.replaceMavenVars(mp, 
"xxx${foo}yyy"));
-    }
-
-    private void setPrivateField(Object obj, String fieldName, Object value) 
throws Exception {
-        Field f;
-        try {
-            f = obj.getClass().getDeclaredField(fieldName);
-        } catch (Exception e) {
-            f = obj.getClass().getSuperclass().getDeclaredField(fieldName);
-        }
-        f.setAccessible(true);
-        f.set(obj, value);
-    }
-}

Reply via email to