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 f705c22  SLING-8046 : Correct and improve classifier handling
f705c22 is described below

commit f705c2296d024230b94a8a96af20966a3d4d689b
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Sun Oct 21 22:10:59 2018 +0200

    SLING-8046 : Correct and improve classifier handling
---
 .../sling/feature/maven/FeatureConstants.java      |   4 -
 .../apache/sling/feature/maven/Preprocessor.java   | 199 +++++++++++----------
 .../apache/sling/feature/maven/ProjectHelper.java  |  80 +++++++++
 .../feature/maven/mojos/AggregateFeaturesMojo.java |  13 +-
 .../feature/maven/mojos/AttachFeaturesMojo.java    |  30 +---
 .../maven/mojos/AggregateFeaturesMojoTest.java     |  48 ++---
 .../resources/aggregate-features/dir/test_v.json   |   2 +-
 .../resources/aggregate-features/dir/test_w.json   |   2 +-
 .../aggregate-features/dir/test_x.feature          |   2 +-
 .../resources/aggregate-features/dir/test_y.json   |   2 +-
 .../resources/aggregate-features/dir/test_z.json   |   2 +-
 .../resources/aggregate-features/dir2/test_w.json  |   2 +-
 .../resources/aggregate-features/dir2/test_y.json  |   2 +-
 .../resources/aggregate-features/dir2/test_z.json  |   2 +-
 .../resources/aggregate-features/dir3/test_y.json  |   2 +-
 .../resources/aggregate-features/dir3/test_z.json  |   2 +-
 .../resources/aggregate-features/dir4/test_t.json  |   2 +-
 .../resources/aggregate-features/dir4/test_u.json  |   2 +-
 .../resources/aggregate-features/dir4/test_v.json  |   2 +-
 .../resources/aggregate-features/dir4/test_w.json  |   2 +-
 .../resources/aggregate-features/dir4/test_x.json  |   2 +-
 .../resources/aggregate-features/dir4/test_y.json  |   2 +-
 .../resources/aggregate-features/dir4/test_z.json  |   2 +-
 23 files changed, 237 insertions(+), 171 deletions(-)

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 61dfed1..189acb8 100644
--- a/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
@@ -19,8 +19,4 @@ package org.apache.sling.feature.maven;
 public abstract class FeatureConstants {
 
     public static final String PACKAGING_FEATURE = "slingfeature";
-
-    public static final String CLASSIFIER_FEATURE = "feature";
-
-    public static final String CLASSIFIER_TEST_FEATURE = "testfeature";
 }
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 d2150c4..7ebd822 100644
--- a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
+++ b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
@@ -23,11 +23,12 @@ import java.io.Reader;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 
 import javax.json.Json;
 import javax.json.JsonObject;
@@ -66,31 +67,8 @@ public class Preprocessor {
                 throw new RuntimeException("Feature project has no feature 
defined: " + finfo.project.getId());
             }
 
-            final Set<String> classifiers = new HashSet<>();
-            boolean foundEmpty = false;
-            for(final Feature f : finfo.features.values()) {
-                if ( f.getId().getClassifier() == null ) {
-                    if ( foundEmpty ) {
-                        throw new RuntimeException("More than one feature file 
without classifier in project " + finfo.project.getId());
-                    }
-                    foundEmpty = true;
-                } else {
-                    if ( classifiers.contains(f.getId().getClassifier()) ) {
-                        throw new RuntimeException("Duplicate feature 
classifier " + f.getId().getClassifier() + " used in project " + 
finfo.project.getId());
-                    }
-                    classifiers.add(f.getId().getClassifier());
-                }
-            }
-            for(final Feature f : finfo.testFeatures.values()) {
-                if ( f.getId().getClassifier() == null ) {
-                   throw new RuntimeException("Found test feature without 
classifier in project " + finfo.project.getId());
-                } else {
-                    if ( classifiers.contains(f.getId().getClassifier()) ) {
-                        throw new RuntimeException("Duplicate (test) feature 
classifier " + f.getId().getClassifier() + " used in project " + 
finfo.project.getId());
-                    }
-                    classifiers.add(f.getId().getClassifier());
-                }
-            }
+            ProjectHelper.validateFeatureClassifiers(finfo.project, 
finfo.features, finfo.testFeatures, null, null);
+
             ProjectHelper.storeProjectInfo(finfo);
         }
     }
@@ -150,23 +128,55 @@ public class Preprocessor {
         }
 
         // assemble features
-        final Map<String, Feature> assembledFeatures = new TreeMap<>();
-        for(final Map.Entry<String, Feature> entry : (config.isTestConfig() ? 
info.testFeatures : info.features).entrySet()) {
-               final Map<String, Feature> featureMap = (config.isTestConfig() 
? info.assembledTestFeatures : info.assembledFeatures);
-               if ( !featureMap.containsKey(entry.getKey())) {
-                   final Feature assembledFeature = 
FeatureBuilder.assemble(entry.getValue(), new 
BuilderContext(this.createFeatureProvider(env,
-                       info,
-                       config.isTestConfig(),
-                       config.isSkipAddDependencies(),
-                       config.getScope(), null)));
-                   featureMap.put(entry.getKey(), assembledFeature);
+        final Map<String, Feature> features = (config.isTestConfig() ? 
info.testFeatures : info.features);
+        final Map<String, Feature> processFeatures = new HashMap<>(features);
+        final Map<String, Feature> aggregatedFeatures = (config.isTestConfig() 
? info.assembledTestFeatures : info.assembledFeatures);
+        while ( aggregatedFeatures.size() < features.size() ) {
+               final int start = aggregatedFeatures.size();
+
+               final Iterator<Map.Entry<String, Feature>> iter = 
processFeatures.entrySet().iterator();
+               while ( iter.hasNext() ) {
+                       final Map.Entry<String, Feature> entry = iter.next();
+                       boolean process = false;
+                       if ( entry.getValue().getInclude() == null ) {
+                               // no include we can process
+                               process = true;
+                       } else {
+                           final ArtifactId include = 
entry.getValue().getInclude().getId();
+                           if ( 
!include.getGroupId().equals(info.project.getGroupId())
+                             || 
!include.getArtifactId().equals(info.project.getArtifactId())
+                             || 
!include.getVersion().equals(info.project.getVersion()) ) {
+                               process = true;
+                           } else {
+                               // same project
+                               for(final Feature f : 
aggregatedFeatures.values()) {
+                                       if ( f.getId().equals(include) ) {
+                                               process = true;
+                                               break;
+                                       }
+                               }
+                           }
+                       }
+                       if ( process ) {
+                               iter.remove();
+                   final Feature assembledFeature = 
FeatureBuilder.assemble(entry.getValue(), new 
BuilderContext(this.createFeatureProvider(env,
+                               info,
+                               config.isTestConfig(),
+                               config.isSkipAddDependencies(),
+                               config.getScope(), null)));
+                   aggregatedFeatures.put(entry.getKey(), assembledFeature);
+                   break;
+                       }
+               }
+               if ( aggregatedFeatures.size() == start ) {
+                       throw new RuntimeException("Circular dependency in 
features in project " + info.project.getId());
                }
         }
 
         if ( config.isSkipAddDependencies() ) {
             env.logger.debug("Not adding artifacts from features as 
dependencies");
         } else {
-            for(final Feature f : assembledFeatures.values()) {
+            for(final Feature f : (config.isTestConfig() ? 
info.assembledTestFeatures : info.assembledFeatures).values()) {
                 addDependenciesFromFeature(env, info, f, config.getScope());
             }
         }
@@ -245,41 +255,7 @@ public class Preprocessor {
                     throw new RuntimeException("Unable to read feature " + 
file.getAbsolutePath(), io);
                 }
 
-                String json = Substitution.replaceMavenVars(info.project, 
sb.toString());
-
-                // check if "id" is set
-                try (final JsonReader reader = Json.createReader(new 
StringReader(json)) ) {
-                       final JsonObject obj = reader.readObject();
-                       if ( !obj.containsKey("id") ) {
-                               final StringBuilder isb = new StringBuilder();
-                               isb.append(info.project.getGroupId());
-                               isb.append(':');
-                               isb.append(info.project.getArtifactId());
-                               isb.append(':');
-                                       
isb.append(FeatureConstants.PACKAGING_FEATURE);
-                               isb.append(':');
-                               final int lastDot = 
file.getName().lastIndexOf('.');
-                               isb.append(file.getName().substring(0, 
lastDot));
-                               isb.append(':');
-                               isb.append(info.project.getVersion());
-
-                        final StringWriter writer = new StringWriter();
-
-                        logger.debug("Generating id " + isb.toString() + " for 
feature file " + file);
-                        try ( final JsonGenerator generator = 
Json.createGenerator(writer) ) {
-                               generator.writeStartObject();
-
-                               generator.write("id", isb.toString());
-
-                               for(final Map.Entry<String, JsonValue> entry : 
obj.entrySet()) {
-                                generator.write(entry.getKey(), 
entry.getValue());
-                               }
-                               generator.writeEnd();
-                        }
-
-                        json = writer.toString();
-                       }
-                }
+                final String json = preprocessFeature(logger, info, config, 
file, sb.toString());
                 try (final Reader reader = new StringReader(json)) {
                     final Feature feature = FeatureJSONReader.read(reader, 
file.getAbsolutePath());
 
@@ -298,6 +274,54 @@ public class Preprocessor {
         }
     }
 
+       protected String preprocessFeature(final Logger logger, final 
FeatureProjectInfo info,
+                       final FeatureProjectConfig config, final File file, 
final String readJson) {
+               String json = Substitution.replaceMavenVars(info.project, 
readJson);
+
+               // check if "id" is set
+               try (final JsonReader reader = Json.createReader(new 
StringReader(json)) ) {
+                       final JsonObject obj = reader.readObject();
+                       if ( !obj.containsKey("id") ) {
+                               final StringBuilder isb = new StringBuilder();
+                               isb.append(info.project.getGroupId());
+                               isb.append(':');
+                               isb.append(info.project.getArtifactId());
+                               isb.append(':');
+                               isb.append(FeatureConstants.PACKAGING_FEATURE);
+                               // if the feature is in the root of the 
configured directory
+                               // and the feature is named "feature.json"
+                               // and the feature is not a test feature, this 
is the main feature
+                               // which does not get a classifier
+                               if ( config.isTestConfig()
+                                        || 
!file.getName().equals("feature.json")
+                                        || 
!file.getParentFile().getAbsolutePath().equals(new 
File(info.project.getBasedir(), config.getFeaturesDir()).getAbsolutePath())) {
+                               isb.append(':');
+                               final int lastDot = 
file.getName().lastIndexOf('.');
+                                   isb.append(file.getName().substring(0, 
lastDot));
+                               }
+                           isb.append(':');
+                               isb.append(info.project.getVersion());
+
+                       final StringWriter writer = new StringWriter();
+
+                       logger.debug("Generating id " + isb.toString() + " for 
feature file " + file);
+                       try ( final JsonGenerator generator = 
Json.createGenerator(writer) ) {
+                               generator.writeStartObject();
+
+                               generator.write("id", isb.toString());
+
+                               for(final Map.Entry<String, JsonValue> entry : 
obj.entrySet()) {
+                               generator.write(entry.getKey(), 
entry.getValue());
+                               }
+                               generator.writeEnd();
+                       }
+
+                       json = writer.toString();
+                       }
+               }
+               return json;
+       }
+
     private void checkFeatureId(final MavenProject project, final Feature 
feature) {
         // check feature id
         if ( !project.getGroupId().equals(feature.getId().getGroupId()) ) {
@@ -348,17 +372,12 @@ public class Preprocessor {
                        final String key = id.getGroupId() + ":" + 
id.getArtifactId();
                        if ( projectKey.equals(key) ) {
                                // this is a feature from the current project
-                               final Map.Entry<String, Feature> found = 
findFeature(info, isTest, id);
+                               final Feature found = findFeature(info, isTest, 
id);
                            if ( found == null ) {
                                env.logger.error("Unable to find included 
feature " + id.toMvnId() + " in project " + info.project);
                                return null;
                            }
-                           Feature f = found.getValue();
-                           if ( !found.getValue().isAssembled() ) {
-                               f = FeatureBuilder.assemble(found.getValue(), 
new BuilderContext(this));
-                               (isTest ? info.assembledTestFeatures : 
info.testFeatures).put(found.getKey(), f);
-                           }
-                           return f;
+                           return found;
                        }
                        // if it's a project from the current reactor build, we 
can't resolve it right now
                        final FeatureProjectInfo depProjectInfo = 
env.modelProjects.get(key);
@@ -371,14 +390,14 @@ public class Preprocessor {
                            } else {
                                process(env, depInfo, 
FeatureProjectConfig.getMainConfig(depInfo));
                            }
-                           final Map.Entry<String, Feature> found = 
findFeature(info, isTest, id);
+                           final Feature found = findFeature(info, isTest, id);
 
                            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.getValue();
+                           return found;
                        } else {
                            env.logger.debug("Found external " + id.getType() + 
" dependency: " + id);
 
@@ -430,28 +449,22 @@ public class Preprocessor {
         }
     }
 
-    private Map.Entry<String, Feature> findFeature(final FeatureProjectInfo 
info, final boolean isTest, final ArtifactId id) {
-       Map.Entry<String, Feature> found = findFeature(isTest ? 
info.assembledTestFeatures : info.assembledFeatures, id);
+    private Feature findFeature(final FeatureProjectInfo info, final boolean 
isTest, final ArtifactId id) {
+       Feature found = findFeature(isTest ? info.assembledTestFeatures : 
info.assembledFeatures, id);
         if ( found == null ) {
                if ( isTest ) {
-                       found = findFeature(info.features, id);
-               }
-               if ( found == null ) {
-                       found = findFeature(isTest ? info.testFeatures : 
info.features, id);
-                       if ( found == null && isTest ) {
-                               found = findFeature(info.features, id);
-                       }
+                       found = findFeature(info.assembledFeatures, id);
                }
         }
         return found;
     }
 
-    private Map.Entry<String, Feature> findFeature(final Map<String, Feature> 
featureMap, final ArtifactId id) {
-       Map.Entry<String, Feature> found = null;
+    private Feature findFeature(final Map<String, Feature> featureMap, final 
ArtifactId id) {
+       Feature found = null;
        if ( featureMap != null ) {
             for(final Map.Entry<String, Feature> f : featureMap.entrySet()) {
                 if ( f.getValue().getId().equals(id) ) {
-                    found = f;
+                    found = f.getValue();
                     break;
                 }
             }
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 d819ffb..ac202c0 100644
--- a/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
+++ b/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
@@ -19,8 +19,11 @@ 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.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -279,4 +282,81 @@ public abstract class ProjectHelper {
             feature.setLicense(license);
         }
     }
+
+    private static final String AGGREGATE_PREFIX = ":aggregate:";
+
+    private static String toString(final List<String> featureKeys) {
+       final StringBuilder sb = new StringBuilder();
+       if ( featureKeys.size() > 1 ) {
+               sb.append('[');
+       }
+        boolean first = true;
+        for(final String key : featureKeys) {
+               if ( first ) {
+                       first = false;
+               } else {
+                       sb.append(", ");
+               }
+               if ( key.startsWith(AGGREGATE_PREFIX) ) {
+                       sb.append("aggregate ");
+                       sb.append(key.substring(AGGREGATE_PREFIX.length()));
+               } else {
+                       sb.append(key);
+               }
+        }
+       if ( featureKeys.size() > 1 ) {
+               sb.append(']');
+       }
+        return sb.toString();
+    }
+
+    public static boolean isAggregate(final String featureKey) {
+       return featureKey.startsWith(AGGREGATE_PREFIX);
+    }
+
+    public static String generateAggregateFeatureKey(final String classifier) {
+       return AGGREGATE_PREFIX.concat(classifier);
+    }
+
+    private static final String NULL_KEY = ":";
+
+    private static void addClassifier(final Map<String, List<String>> 
classifiers, final String classifier, final String featureKey) {
+       final String key = classifier == null ? NULL_KEY : classifier;
+       List<String> list = classifiers.get(key);
+       if ( list == null ) {
+               list = new ArrayList<>();
+               classifiers.put(key, list);
+       }
+       list.add(featureKey);
+    }
+
+    public static void validateFeatureClassifiers(final MavenProject project,
+               final Map<String, Feature> features,
+               final Map<String, Feature> testFeatures,
+               final String additionalFeatureKey,
+               final String additionalClassifier) {
+        final Map<String, List<String>> classifiers = new HashMap<>();
+        for(final Map.Entry<String, Feature> entry : features.entrySet()) {
+               addClassifier(classifiers, 
entry.getValue().getId().getClassifier(), entry.getKey());
+        }
+        for(final Map.Entry<String, Feature> entry : testFeatures.entrySet()) {
+               if ( entry.getValue().getId().getClassifier() == null ) {
+                throw new RuntimeException("Found test feature without 
classifier in project " + project.getId() + " : " + entry.getKey());
+               }
+               addClassifier(classifiers, 
entry.getValue().getId().getClassifier(), entry.getKey());
+        }
+        if ( additionalFeatureKey != null ) {
+               addClassifier(classifiers, additionalClassifier, 
additionalFeatureKey);
+        }
+        for(final Map.Entry<String, List<String>> entry : 
classifiers.entrySet()) {
+               if ( entry.getValue().size() > 1 ) {
+                       if ( entry.getKey().equals(NULL_KEY)) {
+                    throw new RuntimeException("More than one feature file 
without classifier in project " + project.getId() + " : " + 
toString(entry.getValue()));
+                       } else {
+                    throw new RuntimeException("More than one feature file for 
classifier " + entry.getKey() + " in project " + project.getId() + " : " + 
toString(entry.getValue()));
+                       }
+               }
+        }
+
+    }
 }
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojo.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojo.java
index fd3b1a7..6f2c1af 100644
--- 
a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojo.java
+++ 
b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojo.java
@@ -67,8 +67,6 @@ import org.codehaus.plexus.util.AbstractScanner;
 )
 public class AggregateFeaturesMojo extends AbstractFeatureMojo {
 
-    private static final String PREFIX = ":aggregate:";
-
     @Parameter(required = true)
     List<FeatureConfig> aggregates;
 
@@ -97,16 +95,11 @@ public class AggregateFeaturesMojo extends 
AbstractFeatureMojo {
     public void execute() throws MojoExecutionException, MojoFailureException {
         // get map of all project features
         final Map<String, Feature> projectFeatures = 
ProjectHelper.getFeatures(this.project);
-        final String key = PREFIX + aggregateClassifier;
-        if ( projectFeatures.containsKey(key) ) {
-            throw new MojoExecutionException("Duplicate aggregated feature 
definition for classifier " + aggregateClassifier);
-        }
+        final String key = 
ProjectHelper.generateAggregateFeatureKey(aggregateClassifier);
+        ProjectHelper.validateFeatureClassifiers(this.project, 
projectFeatures, ProjectHelper.getTestFeatures(this.project), key, 
aggregateClassifier);
         // ..and hash them by artifact id
         final Map<ArtifactId, Feature> contextFeatures = new HashMap<>();
         for(final Map.Entry<String, Feature> entry : 
projectFeatures.entrySet()) {
-            if ( 
aggregateClassifier.equals(entry.getValue().getId().getClassifier())) {
-                throw new MojoExecutionException("Aggregated feature 
definition is using same classifier as project feature " + aggregateClassifier);
-            }
             contextFeatures.put(entry.getValue().getId(), entry.getValue());
         }
 
@@ -354,7 +347,7 @@ public class AggregateFeaturesMojo extends 
AbstractFeatureMojo {
 
             for ( Map.Entry<String, Feature> entry : features.entrySet() ) {
                 // skip aggregates
-                if ( entry.getKey().startsWith(PREFIX) ) {
+                if ( ProjectHelper.isAggregate(entry.getKey()) ) {
                     continue;
                 }
                 final String name = entry.getKey().substring(prefix.length());
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeaturesMojo.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeaturesMojo.java
index bfe4529..d184ece 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeaturesMojo.java
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeaturesMojo.java
@@ -53,7 +53,7 @@ public class AttachFeaturesMojo extends AbstractFeatureMojo {
             final String classifier)
     throws MojoExecutionException {
         // write the feature
-        final File outputFile = new File(this.getTmpDir(), "feature-" + 
classifier + ".json");
+        final File outputFile = new File(this.getTmpDir(), classifier == null 
? "feature.json" : "feature-" + classifier + ".json");
         outputFile.getParentFile().mkdirs();
 
         try ( final Writer writer = new FileWriter(outputFile)) {
@@ -64,7 +64,7 @@ public class AttachFeaturesMojo extends AbstractFeatureMojo {
 
         // if this project is a feature, it's the main artifact
         if ( project.getPackaging().equals(FeatureConstants.PACKAGING_FEATURE)
-             && (FeatureConstants.CLASSIFIER_FEATURE.equals(classifier))) {
+             && classifier == null) {
             project.getArtifact().setFile(outputFile);
         } else {
             // otherwise attach it as an additional artifact
@@ -75,36 +75,20 @@ public class AttachFeaturesMojo extends AbstractFeatureMojo 
{
 
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
-        final Feature main = 
this.attachClassifierFeatures(ProjectHelper.getFeatures(this.project).values());
-        if ( main != null ) {
-            attach(main, FeatureConstants.CLASSIFIER_FEATURE);
-        }
+        
this.attachClassifierFeatures(ProjectHelper.getFeatures(this.project).values());
 
         if ( this.attachTestFeatures ) {
-               final Feature test = 
this.attachClassifierFeatures(ProjectHelper.getTestFeatures(this.project).values());
-               if ( test != null ) {
-                       attach(test, FeatureConstants.CLASSIFIER_TEST_FEATURE);
-               }
+               
this.attachClassifierFeatures(ProjectHelper.getTestFeatures(this.project).values());
         }
     }
 
     /**
-     * Attach classifier features and return the main non classifier feature
-     * @return
+     * Attach all features
      * @throws MojoExecutionException
      */
-    Feature attachClassifierFeatures(final Collection<Feature> features) 
throws MojoExecutionException {
-        // Find all features that have a classifier and attach each of them
-        Feature main = null;
+    void attachClassifierFeatures(final Collection<Feature> features) throws 
MojoExecutionException {
         for (final Feature f : features) {
-            if (f.getId().getClassifier() == null ) {
-                if ( main == null ) {
-                    main = f;
-                }
-            } else {
-                attach(f, f.getId().getClassifier());
-            }
+            attach(f, f.getId().getClassifier());
         }
-        return main;
     }
 }
diff --git 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojoTest.java
 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojoTest.java
index 82451d7..8421339 100644
--- 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojoTest.java
+++ 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesMojoTest.java
@@ -16,6 +16,29 @@
  */
 package org.apache.sling.feature.maven.mojos;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+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.lang.reflect.Field;
+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.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -39,29 +62,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.lang.reflect.Field;
-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.assertFalse;
-import static org.junit.Assert.assertNotNull;
-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 AggregateFeaturesMojoTest {
     private Path tempDir;
     private static Map<String, ArtifactId> pluginCallbacks;
@@ -444,7 +444,7 @@ public class AggregateFeaturesMojoTest {
 
     @Test
     public void testReadFeatureFromArtifact() throws Exception {
-        File featureFile = new File(
+       File featureFile = new File(
                 
getClass().getResource("/aggregate-features/test_x.json").getFile());
         // read feature
         Map<String, Feature> featureMap = new HashMap<>();
diff --git a/src/test/resources/aggregate-features/dir/test_v.json 
b/src/test/resources/aggregate-features/dir/test_v.json
index 4b09d5d..d3ec7d2 100644
--- a/src/test/resources/aggregate-features/dir/test_v.json
+++ b/src/test/resources/aggregate-features/dir/test_v.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:v:9.9.9",
+  "id":"test:test:9.9.9:v:slingfeature",
   "bundles":[
     "org.apache.sling:someotherbundle:0.9"
   ]
diff --git a/src/test/resources/aggregate-features/dir/test_w.json 
b/src/test/resources/aggregate-features/dir/test_w.json
index 3089f0b..7c09084 100644
--- a/src/test/resources/aggregate-features/dir/test_w.json
+++ b/src/test/resources/aggregate-features/dir/test_w.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:w:9.9.9",
+  "id":"test:test:9.9.9:w:slingfeature",
   "bundles":[
     "org.apache.sling:someotherbundle:1"
   ]
diff --git a/src/test/resources/aggregate-features/dir/test_x.feature 
b/src/test/resources/aggregate-features/dir/test_x.feature
index cd606da..5f90275 100644
--- a/src/test/resources/aggregate-features/dir/test_x.feature
+++ b/src/test/resources/aggregate-features/dir/test_x.feature
@@ -1,5 +1,5 @@
 {
-  "id":"test:x:9.9.9",
+  "id":"test:test:9.9.9:x:slingfeature",
   "bundles":[
     {
       "id":"org.apache.sling:somebundle:1.2.3"
diff --git a/src/test/resources/aggregate-features/dir/test_y.json 
b/src/test/resources/aggregate-features/dir/test_y.json
index 08c5416..54d37bd 100644
--- a/src/test/resources/aggregate-features/dir/test_y.json
+++ b/src/test/resources/aggregate-features/dir/test_y.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:y:9.9.9",
+  "id":"test:test:9.9.9:y:slingfeature",
   "bundles":[
     {
       "id":"org.apache.aries:org.apache.aries.util:1.1.3",
diff --git a/src/test/resources/aggregate-features/dir/test_z.json 
b/src/test/resources/aggregate-features/dir/test_z.json
index 9ad87e5..a08a7d3 100644
--- a/src/test/resources/aggregate-features/dir/test_z.json
+++ b/src/test/resources/aggregate-features/dir/test_z.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:z:1.0.1",
+  "id":"test:test:1.0.1:z:slingfeature",
   "configurations": {
     "some.pid": {
       "x": "y"
diff --git a/src/test/resources/aggregate-features/dir2/test_w.json 
b/src/test/resources/aggregate-features/dir2/test_w.json
index 3089f0b..7c09084 100644
--- a/src/test/resources/aggregate-features/dir2/test_w.json
+++ b/src/test/resources/aggregate-features/dir2/test_w.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:w:9.9.9",
+  "id":"test:test:9.9.9:w:slingfeature",
   "bundles":[
     "org.apache.sling:someotherbundle:1"
   ]
diff --git a/src/test/resources/aggregate-features/dir2/test_y.json 
b/src/test/resources/aggregate-features/dir2/test_y.json
index 08c5416..54d37bd 100644
--- a/src/test/resources/aggregate-features/dir2/test_y.json
+++ b/src/test/resources/aggregate-features/dir2/test_y.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:y:9.9.9",
+  "id":"test:test:9.9.9:y:slingfeature",
   "bundles":[
     {
       "id":"org.apache.aries:org.apache.aries.util:1.1.3",
diff --git a/src/test/resources/aggregate-features/dir2/test_z.json 
b/src/test/resources/aggregate-features/dir2/test_z.json
index 9ad87e5..a08a7d3 100644
--- a/src/test/resources/aggregate-features/dir2/test_z.json
+++ b/src/test/resources/aggregate-features/dir2/test_z.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:z:1.0.1",
+  "id":"test:test:1.0.1:z:slingfeature",
   "configurations": {
     "some.pid": {
       "x": "y"
diff --git a/src/test/resources/aggregate-features/dir3/test_y.json 
b/src/test/resources/aggregate-features/dir3/test_y.json
index b690729..d433d0b 100644
--- a/src/test/resources/aggregate-features/dir3/test_y.json
+++ b/src/test/resources/aggregate-features/dir3/test_y.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:y:9.9.9",
+  "id":"test:test:9.9.9:y:slingfeature",
   "bundles":[
     {
       "id":"org.apache.aries:org.apache.aries.util:1.1.3",
diff --git a/src/test/resources/aggregate-features/dir3/test_z.json 
b/src/test/resources/aggregate-features/dir3/test_z.json
index 27157b5..ce08448 100644
--- a/src/test/resources/aggregate-features/dir3/test_z.json
+++ b/src/test/resources/aggregate-features/dir3/test_z.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:z:1.0.1",
+  "id":"test:test:1.0.1:z:slingfeature",
   "configurations": {
     "some.pid": {
       "x": "y"
diff --git a/src/test/resources/aggregate-features/dir4/test_t.json 
b/src/test/resources/aggregate-features/dir4/test_t.json
index f459d53..a0a0040 100644
--- a/src/test/resources/aggregate-features/dir4/test_t.json
+++ b/src/test/resources/aggregate-features/dir4/test_t.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:t:9.9.9",
+  "id":"test:test:9.9.9:t:slingfeature",
   "configurations": {
     "t.pid": {
       "t": "t"
diff --git a/src/test/resources/aggregate-features/dir4/test_u.json 
b/src/test/resources/aggregate-features/dir4/test_u.json
index 9f8ffb5..423df34 100644
--- a/src/test/resources/aggregate-features/dir4/test_u.json
+++ b/src/test/resources/aggregate-features/dir4/test_u.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:u:9.9.9",
+  "id":"test:test:9.9.9:u:slingfeature",
   "configurations": {
     "u.pid": {
       "u": "u"
diff --git a/src/test/resources/aggregate-features/dir4/test_v.json 
b/src/test/resources/aggregate-features/dir4/test_v.json
index 78269af..1f7d949 100644
--- a/src/test/resources/aggregate-features/dir4/test_v.json
+++ b/src/test/resources/aggregate-features/dir4/test_v.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:v:9.9.9",
+  "id":"test:test:9.9.9:v:slingfeature",
   "configurations": {
     "v.pid": {
       "v": "v"
diff --git a/src/test/resources/aggregate-features/dir4/test_w.json 
b/src/test/resources/aggregate-features/dir4/test_w.json
index 8cf9e79..9590219 100644
--- a/src/test/resources/aggregate-features/dir4/test_w.json
+++ b/src/test/resources/aggregate-features/dir4/test_w.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:w:9.9.9",
+  "id":"test:test:9.9.9:w:slingfeature",
   "configurations": {
     "some.pid": {
       "x": "z"
diff --git a/src/test/resources/aggregate-features/dir4/test_x.json 
b/src/test/resources/aggregate-features/dir4/test_x.json
index 8df875b..ad87706 100644
--- a/src/test/resources/aggregate-features/dir4/test_x.json
+++ b/src/test/resources/aggregate-features/dir4/test_x.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:x:9.9.9",
+  "id":"test:test:9.9.9:x:slingfeature",
   "configurations": {
     "t.pid": {
       "t": "x"
diff --git a/src/test/resources/aggregate-features/dir4/test_y.json 
b/src/test/resources/aggregate-features/dir4/test_y.json
index 4ce4e5e..2bf4bc6 100644
--- a/src/test/resources/aggregate-features/dir4/test_y.json
+++ b/src/test/resources/aggregate-features/dir4/test_y.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:y:9.9.9",
+  "id":"test:test:9.9.9:y:slingfeature",
   "configurations": {
     "v.pid": {
       "v": "y"
diff --git a/src/test/resources/aggregate-features/dir4/test_z.json 
b/src/test/resources/aggregate-features/dir4/test_z.json
index 95103c5..7c266f4 100644
--- a/src/test/resources/aggregate-features/dir4/test_z.json
+++ b/src/test/resources/aggregate-features/dir4/test_z.json
@@ -1,5 +1,5 @@
 {
-  "id":"test:z:1.0.1",
+  "id":"test:test:1.0.1:z:slingfeature",
   "configurations": {
     "z.pid": {
       "z": "z"

Reply via email to