Author: cziegeler
Date: Tue Jul  4 13:53:35 2017
New Revision: 1800787

URL: http://svn.apache.org/viewvc?rev=1800787&view=rev
Log:
Continue implementing application handling

Modified:
    
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
    sling/whiteboard/cziegeler/osgifeature-maven-plugin/pom.xml
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
    
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/resources/META-INF/plexus/components.xml

Modified: 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
 (original)
+++ 
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
 Tue Jul  4 13:53:35 2017
@@ -80,35 +80,34 @@ public class FeatureUtil {
         for(final File f : dir.listFiles()) {
             if ( f.isFile() && !f.getName().startsWith(".")) {
                 // check if file is a reference
-                if ( f.getName().endsWith(".ref") ) {
-                    final List<String> lines = Files.readAllLines(f.toPath());
-                    for(String line : lines) {
-                        line = line.trim();
-                        if ( !line.isEmpty() && !line.startsWith("#") ) {
-                            paths.add(line);
-                        }
-                    }
-                } else if ( f.getName().endsWith(".json")) {
-                    paths.add(f.getAbsolutePath());
+                if ( f.getName().endsWith(".ref") || 
f.getName().endsWith(".json") ) {
+                    processFile(paths, f);
                 }
             }
         }
     }
 
-    private static void processFile(final List<String> paths, final File f)
+    public static List<String> parseFeatureRefFile(final File file)
     throws IOException {
-        if ( f.getName().endsWith(".ref") ) {
-            final List<String> lines = Files.readAllLines(f.toPath());
-            for(String line : lines) {
-                line = line.trim();
-                if ( !line.isEmpty() && !line.startsWith("#") ) {
-                    if ( line.indexOf(':') == -1 ) {
-                        paths.add(new File(line).getAbsolutePath());
-                    } else {
-                        paths.add(line);
-                    }
+        final List<String> result = new ArrayList<>();
+        final List<String> lines = Files.readAllLines(file.toPath());
+        for(String line : lines) {
+            line = line.trim();
+            if ( !line.isEmpty() && !line.startsWith("#") ) {
+                if ( line.indexOf(':') == -1 ) {
+                    result.add(new File(line).getAbsolutePath());
+                } else {
+                    result.add(line);
                 }
             }
+        }
+        return result;
+    }
+
+    private static void processFile(final List<String> paths, final File f)
+    throws IOException {
+        if ( f.getName().endsWith(".ref") ) {
+            paths.addAll(parseFeatureRefFile(f));
         } else {
             paths.add(f.getAbsolutePath());
         }
@@ -140,23 +139,29 @@ public class FeatureUtil {
      */
     public static List<String> getFeatureFiles(final File homeDirectory, final 
String... files) throws IOException {
         String[] featureFiles = files;
-        if ( featureFiles == null || files.length == 0 ) {
+        if ( featureFiles == null || featureFiles.length == 0 ) {
             // Default value - check feature directory otherwise features file
             final File[] candidates = new File[] {
-                    new File("features"),
-                    new File("features.json"),
                     new File(homeDirectory, "features"),
-                    new File(homeDirectory, "features.json")
+                    new File(homeDirectory, "features.json"),
+                    new File("features"),
+                    new File("features.json")
             };
             File f = null;
             for(final File c : candidates) {
-                f = c;
-                if ( f.exists() ) {
+                if ( c.exists() ) {
+                    f = c;
                     break;
                 }
             }
+            // nothing found, we default to the first candidate and fail later
+            if ( f == null ) {
+                f = candidates[0];
+            }
+
             featureFiles = new String[] {f.getAbsolutePath()};
         }
+
         final List<String> paths = new ArrayList<>();
         for(final String name : featureFiles) {
             // check for absolute
@@ -164,21 +169,26 @@ public class FeatureUtil {
                 paths.add(name);
             } else {
                 // file or relative
-                final File[] candidates = {
-                        new File(name),
-                        new File(homeDirectory, name),
-                        new File("features" + File.separatorChar + name),
-                        new File(homeDirectory, "features" + 
File.separatorChar + name)
-                };
                 File f = null;
-                for(final File c : candidates) {
-                    f = c;
-                    if ( c.isAbsolute() || c.exists() ) {
-                        break;
+                final File test = new File(name);
+                if ( test.isAbsolute() ) {
+                    f = test;
+                } else {
+                    final File[] candidates = {
+                            new File(homeDirectory, name),
+                            new File(homeDirectory, "features" + 
File.separatorChar + name),
+                            new File(name),
+                            new File("features" + File.separatorChar + name),
+                    };
+                    for(final File c : candidates) {
+                        if ( c.exists() && c.isFile() ) {
+                            f = c;
+                            break;
+                        }
                     }
                 }
 
-                if ( f.exists() ) {
+                if ( f != null && f.exists() ) {
                     if ( f.isFile() ) {
                         processFile(paths, f);
                     } else {
@@ -186,7 +196,7 @@ public class FeatureUtil {
                     }
                 } else {
                     // we simply add the path and fail later on
-                    paths.add(f.getAbsolutePath());
+                    paths.add(new File(name).getAbsolutePath());
                 }
             }
         }

Modified: sling/whiteboard/cziegeler/osgifeature-maven-plugin/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/pom.xml?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- sling/whiteboard/cziegeler/osgifeature-maven-plugin/pom.xml (original)
+++ sling/whiteboard/cziegeler/osgifeature-maven-plugin/pom.xml Tue Jul  4 
13:53:35 2017
@@ -55,7 +55,7 @@
             <plugin>
                 <groupId>org.codehaus.plexus</groupId>
                 <artifactId>plexus-component-metadata</artifactId>
-                <version>1.5.5</version>
+                <version>1.7.1</version>
                 <executions>
                     <execution>
                         <id>generate-metadata</id>
@@ -114,6 +114,11 @@
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.support</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-core</artifactId>
             <version>${maven.version}</version>
@@ -136,7 +141,7 @@
         <dependency>
             <groupId>org.apache.maven.plugin-tools</groupId>
             <artifactId>maven-plugin-annotations</artifactId>
-            <version>3.4</version>
+            <version>3.5</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -147,38 +152,22 @@
         <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-archiver</artifactId>
-            <version>2.4.4</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.codehaus.plexus</groupId>
-                    <artifactId>plexus-container-default</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.codehaus.plexus</groupId>
-                    <artifactId>plexus-component-api</artifactId>
-                </exclusion>
-            </exclusions>
+            <version>3.5</version>
         </dependency>
         <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-utils</artifactId>
-            <version>3.0.17</version>
+            <version>3.0.24</version>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.4</version>
+            <version>2.5</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven.shared</groupId>
             <artifactId>maven-filtering</artifactId>
-            <version>1.2</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>maven-project</artifactId>
-                    <groupId>org.apache.maven</groupId>
-                </exclusion>
-            </exclusions>
+            <version>3.1.1</version>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
 Tue Jul  4 13:53:35 2017
@@ -24,12 +24,22 @@ public class ApplicationProjectConfig {
 
     public static final String CFG_TEST_FEATURES = "testFeatures";
 
-    public static final String DEFAULT_FEATURE_DIR = "src/main/osgi";
+    public static final String CFG_FEATURE_REFS = "featureRefs";
 
-    public static final String DEFAULT_TEST_FEATURE_DIR = "src/test/osgi";
+    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;
@@ -49,25 +59,32 @@ public class ApplicationProjectConfig {
     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, defaultDir);
+        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());
     }
@@ -80,6 +97,10 @@ public class ApplicationProjectConfig {
         return this.featuresDirName;
     }
 
+    public String getFeatureRefDir() {
+        return this.featuresDirName;
+    }
+
     public boolean isSkipAddDependencies() {
         return this.skipAddDep;
     }

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
 Tue Jul  4 13:53:35 2017
@@ -24,5 +24,14 @@ public class ApplicationProjectInfo exte
 
     public List<Feature> features;
     public List<Feature> testFeatures;
+
+    public List<Feature> featureRefs;
+    public List<Feature> testFeatureRefs;
+
+    public List<Feature> assembledFeatures;
+    public List<Feature> assembledtestFeatures;
+
+    public List<Feature> assembledFeatureRefs;
+    public List<Feature> assembledTestFeatureRefs;
 }
 

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
 Tue Jul  4 13:53:35 2017
@@ -20,7 +20,8 @@ import org.apache.sling.feature.Feature;
 
 public class FeatureProjectInfo extends ProjectInfo {
 
-    public boolean done = false;
+    public boolean featureDone = false;
+    public boolean testFeatureDone = false;
 
     public Feature feature;
     public Feature assembledFeature;

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
 Tue Jul  4 13:53:35 2017
@@ -24,6 +24,7 @@ import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
@@ -35,6 +36,7 @@ import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.json.FeatureJSONReader;
 import org.apache.sling.feature.process.FeatureBuilder;
 import org.apache.sling.feature.process.FeatureProvider;
+import org.apache.sling.feature.support.FeatureUtil;
 import org.codehaus.plexus.logging.Logger;
 
 /**
@@ -61,6 +63,8 @@ public class Preprocessor {
                 final ApplicationProjectInfo ainfo = 
(ApplicationProjectInfo)info;
                 process(env, ainfo, 
ApplicationProjectConfig.getMainConfig(ainfo));
                 process(env, ainfo, 
ApplicationProjectConfig.getTestConfig(ainfo));
+
+                ProjectHelper.storeProjectInfo(ainfo);
             }
         }
     }
@@ -75,12 +79,17 @@ public class Preprocessor {
     private void process(final Environment env,
             final FeatureProjectInfo info,
             final FeatureProjectConfig config) {
-        if ( info.done == true ) {
-            env.logger.debug("Return assembled feature for " + 
info.project.getId());
+        if ( (config.isTestConfig() && info.testFeatureDone == true )
+             || (!config.isTestConfig() && info.featureDone == true) ) {
+            env.logger.debug("Return assembled " + config.getName() + " for " 
+ info.project.getId());
             return;
         }
         // prevent recursion and multiple processing
-        info.done = true;
+        if ( config.isTestConfig() ) {
+            info.testFeatureDone = true;
+        } else {
+            info.featureDone = true;
+        }
         env.logger.debug("Processing " + config.getName() + " in project " + 
info.project.getId());
 
         // read project feature, either inlined or from file
@@ -95,7 +104,7 @@ public class Preprocessor {
             info.feature = feature;
         }
 
-        // process attachments
+        // process attachments (only for jar or bundle)
         if ( "jar".equals(info.project.getPackaging())
              || "bundle".equals(info.project.getPackaging())) {
             if ( config.isSkipAddJarToFeature() ) {
@@ -110,55 +119,12 @@ public class Preprocessor {
             }
         }
 
-        final Feature assembledFeature = FeatureBuilder.assemble(feature, new 
FeatureProvider() {
-
-            @Override
-            public Feature provide(final ArtifactId id) {
-
-                final Dependency dep = ProjectHelper.toDependency(id, 
config.getScope());
-                if ( !config.isSkipAddDependencies() ) {
-
-                    env.logger.debug("- adding feature dependency " + 
id.toMvnId());
-                    info.project.getDependencies().add(dep);
-                }
-
-                // 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 FeatureProjectInfo depInfo = 
(FeatureProjectInfo)env.modelProjects.get(key);
-                if ( depInfo != null ) {
-                    env.logger.debug("Found reactor " + id.getType() + " 
dependency : " + id);
-                    if ( !(depInfo instanceof FeatureProjectInfo) ) {
-                        env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Feature dependency is not a feature project " + 
info.project);
-                        return null;
-                    }
-                    process(env, depInfo, config);
-                    if ( config.isTestConfig() && depInfo.assembledTestFeature 
== null ) {
-                        env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive test feature dependency list including project " + 
info.project);
-                    } else if ( !config.isTestConfig() && 
depInfo.assembledFeature == null ) {
-                        env.logger.error("Unable to get feature " + 
id.toMvnId() + " : Recursive feature dependency list including project " + 
info.project);
-                    } else {
-
-                        if ( config.isTestConfig() ) {
-                            return depInfo.testFeature;
-                        } else {
-                            return depInfo.feature;
-                        }
-                    }
-                } else {
-                    env.logger.debug("Found external " + id.getType() + " 
dependency: " + id);
-
-                    // "external" dependency, we can already resolve it
-                    final File featureFile = 
ProjectHelper.getOrResolveArtifact(info.project, env.session, 
env.artifactHandlerManager, env.resolver, id).getFile();
-                    try (final FileReader r = new FileReader(featureFile)) {
-                        return FeatureJSONReader.read(r, 
featureFile.getAbsolutePath());
-                    } catch ( final IOException ioe) {
-                        env.logger.error("Unable to read feature file from " + 
featureFile, ioe);
-                    }
-                }
-
-                return null;
-            }
-        });
+        final Feature assembledFeature = FeatureBuilder.assemble(feature, 
this.createFeatureProvider(env,
+                info,
+                config.isTestConfig(),
+                config.isSkipAddDependencies(),
+                config.getScope(),
+                null));
         if ( config.isTestConfig() ) {
             info.assembledTestFeature = assembledFeature;
         } else {
@@ -172,6 +138,18 @@ public class Preprocessor {
         }
     }
 
+    private void scan(final List<File> files, final File dir, final String 
ext) {
+        for(final File f : dir.listFiles()) {
+            if ( !f.getName().startsWith(".") ) {
+                if ( f.isDirectory() ) {
+                    scan(files, f, ext);
+                } else if ( f.getName().endsWith("." + ext) ) {
+                    files.add(f);
+                }
+            }
+        }
+    }
+
     /**
      * Process a single application project.
      *
@@ -185,20 +163,124 @@ public class Preprocessor {
         final List<Feature> featureList = new ArrayList<>();
         env.logger.debug("Processing " + config.getName() + " in project " + 
info.project.getId());
 
-        // read project features, either inlined or from file
-        // TODO
+        // 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, 
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 = 
FeatureUtil.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, 
this.createFeatureProvider(env,
+                    info,
+                    config.isTestConfig(),
+                    config.isSkipAddDependencies(),
+                    config.getScope(),
+                    featureList));
+            assembledFeatureRefList.add(assembledFeature);
+        }
         if ( config.isTestConfig() ) {
-            info.testFeatures.addAll(featureList);
+            info.testFeatureRefs = featureRefList;
+            info.assembledTestFeatureRefs = assembledFeatureRefList;
         } else {
-            info.features.addAll(featureList);
+            info.featureRefs = featureRefList;
+            info.assembledFeatureRefs = assembledFeatureRefList;
         }
 
         if ( config.isSkipAddDependencies() ) {
             env.logger.debug("Not adding artifacts from features as 
dependencies");
         } else {
-            for(final Feature feature : featureList) {
+            for(final Feature feature : assembledFeatureList) {
+                addDependenciesFromFeature(env, info, feature, 
config.getScope());
+            }
+            for(final Feature feature : assembledFeatureRefList) {
                 addDependenciesFromFeature(env, info, feature, 
config.getScope());
             }
         }
@@ -288,10 +370,8 @@ public class Preprocessor {
         final Feature feature;
         if ( config.getInlinedFeature() != null ) {
             logger.debug("Reading inlined model from project " + 
project.getId());
-            try {
-                try (final Reader reader = new 
StringReader(config.getInlinedFeature())) {
-                    feature = FeatureJSONReader.read(reader, id, null);
-                }
+            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);
             }
@@ -301,15 +381,21 @@ public class Preprocessor {
                 return null;
             }
             logger.debug("Reading feature " + featureFile + " in project " + 
project.getId());
-            try {
-                try (final FileReader reader = new FileReader(featureFile)) {
-                    feature = FeatureJSONReader.read(reader, id, 
featureFile.getAbsolutePath());
-                }
+            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);
             }
         }
+        this.checkFeatureId(id, feature);
+
+        this.setProjectInfo(project, feature);
 
+        // post process and return
+        return postProcessReadFeature(feature);
+    }
+
+    private void checkFeatureId(final ArtifactId id, 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());
@@ -320,9 +406,6 @@ public class Preprocessor {
         if ( !id.getVersion().equals(feature.getId().getVersion()) ) {
             throw new RuntimeException("Wrong version for feature. It should 
be " + id.getVersion() + " but is " + feature.getId().getVersion());
         }
-
-        // post process and return
-        return postProcessReadFeature(feature);
     }
 
     /**
@@ -333,4 +416,103 @@ public class Preprocessor {
     protected Feature postProcessReadFeature(final Feature result)  {
         return result;
     }
+
+    protected void setProjectInfo(final MavenProject project, final Feature 
feature) {
+        // set title, description, vendor, license
+        if ( feature.getTitle() == null ) {
+            feature.setTitle(project.getName());
+        }
+        if ( feature.getDescription() == null ) {
+            feature.setDescription(project.getDescription());
+        }
+        if ( feature.getVendor() == null && project.getOrganization() != null 
) {
+            feature.setVendor(project.getOrganization().getName());
+        }
+        if ( feature.getLicense() == null
+             && project.getLicenses() != null
+             && !project.getLicenses().isEmpty()) {
+            final String license = project.getLicenses().stream()
+                    .filter(l -> l.getName() != null )
+                    .map(l -> l.getName())
+                    .collect(Collectors.joining(", "));
+
+            feature.setLicense(license);
+        }
+    }
+
+    protected FeatureProvider createFeatureProvider(final Environment env,
+            final ProjectInfo info,
+            final boolean isTest,
+            final boolean skipAddDependencies,
+            final String dependencyScope,
+            final List<Feature> projectFeatures) {
+        return new FeatureProvider() {
+
+            @Override
+            public Feature provide(final ArtifactId id) {
+
+                final Dependency dep = ProjectHelper.toDependency(id, 
dependencyScope);
+                if ( !skipAddDependencies ) {
+
+                    env.logger.debug("- adding feature dependency " + 
id.toMvnId());
+                    info.project.getDependencies().add(dep);
+                }
+
+                // 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);
+                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;
+                            }
+                        }
+                    } 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;
+                                }
+                            }
+                        }
+                        return null;
+                    }
+                } else {
+                    env.logger.debug("Found external " + id.getType() + " 
dependency: " + id);
+
+                    // "external" dependency, we can already resolve it
+                    final File featureFile = 
ProjectHelper.getOrResolveArtifact(info.project, env.session, 
env.artifactHandlerManager, env.resolver, id).getFile();
+                    try (final FileReader r = new FileReader(featureFile)) {
+                        return FeatureJSONReader.read(r, 
featureFile.getAbsolutePath());
+                    } catch ( final IOException ioe) {
+                        env.logger.error("Unable to read feature file from " + 
featureFile, ioe);
+                    }
+                }
+
+                return null;
+            }
+        };
+    }
 }

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
 Tue Jul  4 13:53:35 2017
@@ -103,6 +103,15 @@ public abstract class ProjectHelper {
     }
 
     /**
+     * Store all relevant information about the project for plugins to be
+     * retrieved
+     * @param info The project info
+     */
+    public static void storeProjectInfo(final ApplicationProjectInfo info) {
+        // TODO
+    }
+
+    /**
      * Get the assembled feature from the project
      * @param project The maven projet
      * @return The assembled feature or {@code null}

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
 Tue Jul  4 13:53:35 2017
@@ -40,7 +40,7 @@ import org.codehaus.plexus.logging.Logge
 public class DependencyLifecycleParticipant extends 
AbstractMavenLifecycleParticipant {
 
     /**
-     *  the plugin ID consists of <code>groupId:artifactId</code>, see {@link 
Plugin#constructKey(String, String)}
+     * The plugin ID consists of <code>groupId:artifactId</code>, see {@link 
Plugin#constructKey(String, String)}
      */
     private static final String PLUGIN_ID = 
"org.apache.sling:osgifeature-maven-plugin";
 
@@ -65,13 +65,13 @@ public class DependencyLifecycleParticip
         env.logger = logger;
         env.session = session;
 
-        logger.debug("Searching for project leveraging plugin '" + PLUGIN_ID + 
"'...");
+        logger.debug("Searching for project using plugin '" + PLUGIN_ID + 
"'...");
 
         for (final MavenProject project : session.getProjects()) {
             // consider all projects where this plugin is configured
             Plugin plugin = project.getPlugin(PLUGIN_ID);
             if (plugin != null) {
-                logger.debug("Found project " + project + " leveraging " + 
PLUGIN_ID +".");
+                logger.debug("Found project " + project.getId() + " using " + 
PLUGIN_ID);
                 final ProjectInfo info;
                 if ( 
FeatureConstants.PACKAGING_APPLICATION.equals(project.getPackaging()) ) {
                     info = new ApplicationProjectInfo();

Modified: 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/resources/META-INF/plexus/components.xml
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/resources/META-INF/plexus/components.xml?rev=1800787&r1=1800786&r2=1800787&view=diff
==============================================================================
--- 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/resources/META-INF/plexus/components.xml
 (original)
+++ 
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/resources/META-INF/plexus/components.xml
 Tue Jul  4 13:53:35 2017
@@ -95,7 +95,7 @@
         <type>osgijar</type>
         <includesDependencies>false</includesDependencies>
         <language>java</language>
-        <extension>osgijar</extension>
+        <extension>zip</extension>
         <addedToClasspath>false</addedToClasspath>
       </configuration>
     </component>


Reply via email to