SLING-4728 - support slingfeature/slingstart artifact types, mapped to txt for resolution

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1686217 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java b/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java
index 521ee56..b7cedd3 100644
--- a/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java
+++ b/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java
@@ -20,11 +20,29 @@
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.sling.provisioning.model.Artifact;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /** Resolve artifacts using Maven URLs - assumes Pax URL is installed */ 
 public class MavenResolver {
+    public static final String SLINGFEATURE_ARTIFACT_TYPE = "slingfeature";
+    public static final String SLINGSTART_ARTIFACT_TYPE = "slingstart";
+    public static final String TXT_ARTIFACT_TYPE = "txt";
+    
+    private static final Logger log = LoggerFactory.getLogger(MavenResolver.class);
+    
+    @SuppressWarnings("serial")
+    private static final Map <String, String> ARTIFACT_TYPES_MAP = new HashMap<String,String>() {
+        {
+            put(SLINGFEATURE_ARTIFACT_TYPE, TXT_ARTIFACT_TYPE);
+            put(SLINGSTART_ARTIFACT_TYPE, TXT_ARTIFACT_TYPE);
+        }
+    };
+    
     public static void setup() {
         // Enable pax URL for mvn: protocol
         System.setProperty( "java.protocol.handler.pkgs", "org.ops4j.pax.url" );
@@ -41,7 +59,7 @@
         .append(a.getVersion());
         
         if(a.getType() != null) {
-            sb.append("/").append(a.getType());
+            sb.append("/").append(mapArtifactType(a.getType()));
         }
         
         if(a.getClassifier() != null) {
@@ -51,6 +69,19 @@
         return sb.toString();
     }
     
+    /** Maven plugins can map artifact types to well-known
+     *  extensions during deployment - this implements the
+     *  same mapping.
+     */   
+    public static String mapArtifactType(String artifactType) {
+        final String mapped = ARTIFACT_TYPES_MAP.get(artifactType);
+        if(mapped != null) {
+            log.info("artifact type '{}' mapped to '{}' for resolution", artifactType, mapped);
+            return mapped;
+        }
+        return artifactType;
+    }
+    
     public static InputStream resolve(Artifact a) throws MalformedURLException, IOException {
         return new URL(mvnUrl(a)).openStream();
     }
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java b/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java
index 6bc285a..9d0987e 100644
--- a/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java
+++ b/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java
@@ -37,10 +37,6 @@
     private final Logger log = LoggerFactory.getLogger(getClass());
     private List<Artifact> toMerge;
     
-    public static final String SLINGSTART = "slingstart";
-    public static final String SLINGFEATURE = "slingfeature";
-    public static final String NESTED_MODELS = "nested.models";
-    
     public NestedModelsMerger(Model m) {
         super(m);
     }
@@ -72,20 +68,22 @@
         }
     }
     
+    boolean isNestedModel(Artifact a) {
+        final String aType = a.getType();
+        final String classifier = a.getClassifier();
+        final boolean result = 
+                MavenResolver.SLINGFEATURE_ARTIFACT_TYPE.equals(aType)
+                || MavenResolver.SLINGFEATURE_ARTIFACT_TYPE.equals(classifier)
+                || MavenResolver.SLINGSTART_ARTIFACT_TYPE.equals(aType)
+                || MavenResolver.SLINGSTART_ARTIFACT_TYPE.equals(classifier);
+        return result;
+    }
+    
     @Override
     protected void visitArtifact(Feature f, RunMode rm, ArtifactGroup g, Artifact a) throws Exception {
-        // TODO how to identify a nested model when it's the main artifact of a module,
-        // so doesn't have a slingfeature/slingstart type or classifier in its artifact URL?
-        final String str = f.getVariables().get(NESTED_MODELS);
-        if(str == null || str.length() == 0) {
-            return;
-        }
-        final String [] nm = str.split(",");
-        for(String nested : nm) {
-            if(nested.equals(a.getArtifactId())) {
-                log.info("{} feature variable identifies artifact as a nested model , will be merged: {}", f.getName() + "/" + NESTED_MODELS, a);
-                toMerge.add(a);
-            }
+        if(isNestedModel(a)) {
+            log.info("Artifact identified as a nested model , will be merged: {}", a);
+            toMerge.add(a);
         }
     }
 }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/crankstart/launcher/NestedModelsMergerTest.java b/src/test/java/org/apache/sling/crankstart/launcher/NestedModelsMergerTest.java
new file mode 100644
index 0000000..005946b
--- /dev/null
+++ b/src/test/java/org/apache/sling/crankstart/launcher/NestedModelsMergerTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.crankstart.launcher;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.sling.provisioning.model.Artifact;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NestedModelsMergerTest {
+    private final NestedModelsMerger merger = new NestedModelsMerger(null);
+    private final Artifact testArtifact;
+    private final boolean expectNestedModel;
+    
+    @Parameters(name="{0}/{1}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {   
+                { "txt", "slingfeature", true },
+                { "txt", "slingstart", true },
+                { "slingfeature", null, true },
+                { "slingstart", null, true },
+                { "txt", null, false }
+        });
+    }
+    
+    public NestedModelsMergerTest(String aType, String classifier, boolean expectNestedModel) {
+        testArtifact = new Artifact("GID", "AId", "VERSION", classifier, aType);
+        this.expectNestedModel = expectNestedModel;
+    }
+    
+    @Test
+    public void testNestedModelOrNot() {
+        if(expectNestedModel) {
+            assertTrue("Expecting a nested model for " + testArtifact, merger.isNestedModel(testArtifact));
+        } else {
+            assertFalse("Not expecting a nested model for " + testArtifact, merger.isNestedModel(testArtifact));
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/resources/provisioning-model/crankstart-tests.txt b/src/test/resources/provisioning-model/crankstart-tests.txt
index ad7a992..2c8396a 100644
--- a/src/test/resources/provisioning-model/crankstart-tests.txt
+++ b/src/test/resources/provisioning-model/crankstart-tests.txt
@@ -19,11 +19,6 @@
 
 [feature name=crankstart.tests]
 
-[variables]
-  # TODO shouldn't be needed, remove once the mapping of slingfeature/slingstart
-  # artifact types to txt extension is implemented.
-  nested.models=org.apache.sling.cransktart.test.model
-
 [artifacts]
   org.apache.sling/org.apache.sling.crankstart.test.services/1.9.9-SNAPSHOT
   org.apache.sling/org.apache.sling.junit.core/1.0.10
@@ -31,7 +26,7 @@
   org.apache.sling/org.apache.sling.settings/1.3.6
   
   # Test a nested model file
-  org.apache.sling/org.apache.sling.cransktart.test.model/1.9.9-SNAPSHOT/txt
+  org.apache.sling/org.apache.sling.cransktart.test.model/1.9.9-SNAPSHOT/slingfeature
 
 [artifacts runModes=A]
   org.apache.sling/org.apache.sling.api/2.9.0
diff --git a/src/test/resources/sling-launchpad.txt b/src/test/resources/sling-launchpad.txt
index 74b99e8..c2cc7dd 100644
--- a/src/test/resources/sling-launchpad.txt
+++ b/src/test/resources/sling-launchpad.txt
@@ -30,11 +30,6 @@
  
 [feature name=sling.launchpad]
 
-[variables]
-  # TODO shouldn't be needed, remove once the mapping of slingfeature/slingstart
-  # artifact types to txt extension is implemented.
-  nested.models=org.apache.sling.launchpad,org.apache.sling.launchpad.test-bundles
-
 [settings]
   org.apache.sling.commons.log.julenabled=true