SLING-4728 - support nested provisioning models (not fully tested yet)
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1685564 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 7831805..804ab53 100644
--- a/pom.xml
+++ b/pom.xml
@@ -135,7 +135,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.provisioning.model</artifactId>
- <version>1.1.0</version>
+ <version>1.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/ArtifactsVisitor.java b/src/main/java/org/apache/sling/crankstart/launcher/ArtifactsVisitor.java
index dd3e0e6..f3a41a9 100644
--- a/src/main/java/org/apache/sling/crankstart/launcher/ArtifactsVisitor.java
+++ b/src/main/java/org/apache/sling/crankstart/launcher/ArtifactsVisitor.java
@@ -24,7 +24,7 @@
/** Visit the Artifacts of a Model */
public abstract class ArtifactsVisitor {
- private final Model model;
+ protected final Model model;
public ArtifactsVisitor(Model m) {
model = m;
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/Launcher.java b/src/main/java/org/apache/sling/crankstart/launcher/Launcher.java
index abf2616..cedc244 100644
--- a/src/main/java/org/apache/sling/crankstart/launcher/Launcher.java
+++ b/src/main/java/org/apache/sling/crankstart/launcher/Launcher.java
@@ -38,16 +38,16 @@
import org.apache.sling.provisioning.model.Feature;
import org.apache.sling.provisioning.model.Model;
import org.apache.sling.provisioning.model.ModelUtility;
-import org.apache.sling.provisioning.model.RunMode;
import org.apache.sling.provisioning.model.ModelUtility.VariableResolver;
+import org.apache.sling.provisioning.model.RunMode;
import org.apache.sling.provisioning.model.io.ModelReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Launch an OSGi app instance using the Sling provisioning model */
public class Launcher {
- private final Model model = new Model();
- private final Logger log = LoggerFactory.getLogger(getClass());
+ private Model model = new Model();
+ private static final Logger log = LoggerFactory.getLogger(Launcher.class);
public static final String CRANKSTART_FEATURE = ":crankstart";
public static final String MODEL_KEY = "model";
@@ -85,7 +85,9 @@
}
};
- public Launcher(String ... args) throws IOException {
+ public Launcher(String ... args) throws Exception {
+ MavenResolver.setup();
+
// Find all files to read and sort the list, to be deterministic
final SortedSet<File> toRead = new TreeSet<File>();
@@ -100,19 +102,32 @@
toRead.add(f);
}
}
-
+
+ // Merge all model files
for(File f : toRead) {
mergeModel(f);
}
+
+ // And merge nested models (supporting one level of nesting only so far)
+ new NestedModelsMerger(model).visit();
+ computeEffectiveModel();
+ }
+
+ public void computeEffectiveModel() {
+ model = ModelUtility.getEffectiveModel(model, overridingVariableResolver);
+ }
+
+ public Model getModel() {
+ return model;
}
/** Can be called before launch() to read and merge additional models.
* @param r provisioning model to read, closed by this method after reading */
- public void mergeModel(Reader r, String sourceInfo) throws IOException {
+ public static void mergeModel(Model mergeInto, Reader r, String sourceInfo) throws IOException {
+ log.info("Merging provisioning model {}", sourceInfo);
try {
- log.info("Merging provisioning model {}", sourceInfo);
final Model m = ModelReader.read(r, sourceInfo);
- ModelUtility.merge(model, ModelUtility.getEffectiveModel(m, overridingVariableResolver));
+ ModelUtility.merge(mergeInto, m);
} finally {
r.close();
}
@@ -120,13 +135,10 @@
/** Can be called before launch() to read and merge additional models */
public void mergeModel(File f) throws IOException {
- mergeModel(new BufferedReader(new FileReader(f)), f.getAbsolutePath());
+ mergeModel(model, new BufferedReader(new FileReader(f)), f.getAbsolutePath());
}
public void launch() throws Exception {
- // Enable pax URL for mvn: protocol
- System.setProperty( "java.protocol.handler.pkgs", "org.ops4j.pax.url" );
-
// Setup initial classpath to launch the OSGi framework
for(URL u : getClasspathURLs(model, CRANKSTART_FEATURE)) {
addToClasspath(u);
@@ -165,7 +177,7 @@
for(RunMode rm : f.getRunModes()) {
for(ArtifactGroup g : rm.getArtifactGroups()) {
for(Artifact a : g) {
- final String url = mvnUrl(a);
+ final String url = MavenResolver.mvnUrl(a);
try {
result.add(new URL(url));
} catch(MalformedURLException e) {
@@ -180,10 +192,6 @@
return result;
}
- public static String mvnUrl(Artifact a) {
- return "mvn:" + a.getGroupId() + "/" + a.getArtifactId() + "/" + a.getVersion();
- }
-
public static void main(String [] args) throws Exception {
if(args.length < 1) {
System.err.println("Usage: " + Launcher.class.getSimpleName() + " provisioning-model [provisioning-model ...]");
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java b/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java
new file mode 100644
index 0000000..521ee56
--- /dev/null
+++ b/src/main/java/org/apache/sling/crankstart/launcher/MavenResolver.java
@@ -0,0 +1,57 @@
+/*
+ * 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 java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.sling.provisioning.model.Artifact;
+
+/** Resolve artifacts using Maven URLs - assumes Pax URL is installed */
+public class MavenResolver {
+ public static void setup() {
+ // Enable pax URL for mvn: protocol
+ System.setProperty( "java.protocol.handler.pkgs", "org.ops4j.pax.url" );
+ }
+
+ public static String mvnUrl(Artifact a) {
+ final StringBuilder sb = new StringBuilder();
+ sb
+ .append("mvn:")
+ .append(a.getGroupId())
+ .append("/")
+ .append(a.getArtifactId())
+ .append("/")
+ .append(a.getVersion());
+
+ if(a.getType() != null) {
+ sb.append("/").append(a.getType());
+ }
+
+ if(a.getClassifier() != null) {
+ sb.append("/").append(a.getClassifier());
+ }
+
+ return sb.toString();
+ }
+
+ public static InputStream resolve(Artifact a) throws MalformedURLException, IOException {
+ return new URL(mvnUrl(a)).openStream();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java b/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java
new file mode 100644
index 0000000..dec9f2c
--- /dev/null
+++ b/src/main/java/org/apache/sling/crankstart/launcher/NestedModelsMerger.java
@@ -0,0 +1,78 @@
+/*
+ * 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 java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.RunMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/** Merge nested models, provided by slingfeature/slingstart artifacts */
+public class NestedModelsMerger extends ArtifactsVisitor {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private List<Artifact> toMerge;
+
+ public NestedModelsMerger(Model m) {
+ super(m);
+ }
+
+ @Override
+ public synchronized void visit() throws Exception {
+ toMerge = new ArrayList<Artifact>();
+ super.visit();
+ log.info("{} nested models found in provisioning model", toMerge.size());
+
+ for(Artifact a : toMerge) {
+ log.info("Resolving and merging nested model {}", a);
+ InputStream is = null;
+ Reader r = null;
+ try {
+ is = MavenResolver.resolve(a);
+ r = new InputStreamReader(is);
+ Launcher.mergeModel(model, r, a.toString());
+ } catch(Exception e) {
+ log.error("Failed to read nested model " + a, e);
+ } finally {
+ if(r != null) {
+ r.close();
+ }
+ if(is != null) {
+ is.close();
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void visitArtifact(Feature f, RunMode rm, ArtifactGroup g, Artifact a) throws Exception {
+ final String classifier = a.getClassifier();
+ if("slingstart".equals(classifier ) || "slingfeature".equals(classifier)) {
+ toMerge.add(a);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/crankstart/launcher/BasicLauncherIT.java b/src/test/java/org/apache/sling/crankstart/launcher/BasicLauncherIT.java
index 70ba369..5847aac 100644
--- a/src/test/java/org/apache/sling/crankstart/launcher/BasicLauncherIT.java
+++ b/src/test/java/org/apache/sling/crankstart/launcher/BasicLauncherIT.java
@@ -34,7 +34,7 @@
public final RetryRule retryRule = new RetryRule();
@BeforeClass
- public static void setupClass() throws IOException {
+ public static void setupClass() throws Exception {
C = new CrankstartSetup();
C.setup();
osgiConsole = new WebconsoleClient(C.getBaseUrl(), U.ADMIN, U.ADMIN);
diff --git a/src/test/java/org/apache/sling/crankstart/launcher/CrankstartSetup.java b/src/test/java/org/apache/sling/crankstart/launcher/CrankstartSetup.java
index 04bdb2d..4b8f3af 100644
--- a/src/test/java/org/apache/sling/crankstart/launcher/CrankstartSetup.java
+++ b/src/test/java/org/apache/sling/crankstart/launcher/CrankstartSetup.java
@@ -61,12 +61,13 @@
return result;
}
- private static void mergeModelResource(Launcher launcher, String path) throws IOException {
+ private static void mergeModelResource(Launcher launcher, String path) throws Exception {
final InputStream is = CrankstartSetup.class.getResourceAsStream(path);
assertNotNull("Expecting test resource to be found:" + path, is);
final Reader input = new InputStreamReader(is);
try {
- launcher.mergeModel(input, path);
+ Launcher.mergeModel(launcher.getModel(), input, path);
+ launcher.computeEffectiveModel();
} finally {
input.close();
}
@@ -76,7 +77,7 @@
return baseUrl;
}
- synchronized void setup() throws IOException {
+ synchronized void setup() throws Exception {
if(crankstartThread != null) {
return;
}
diff --git a/src/test/java/org/apache/sling/crankstart/launcher/RunModeAIT.java b/src/test/java/org/apache/sling/crankstart/launcher/RunModeAIT.java
index 552756b..99ed68b 100644
--- a/src/test/java/org/apache/sling/crankstart/launcher/RunModeAIT.java
+++ b/src/test/java/org/apache/sling/crankstart/launcher/RunModeAIT.java
@@ -26,7 +26,7 @@
public final RetryRule retryRule = new RetryRule();
@BeforeClass
- public static void setupClass() throws IOException {
+ public static void setupClass() throws Exception {
System.setProperty(RunModeFilter.SLING_RUN_MODES, RUN_MODES);
C.setup();
osgiConsole = new WebconsoleClient(C.getBaseUrl(), U.ADMIN, U.ADMIN);
diff --git a/src/test/java/org/apache/sling/crankstart/launcher/RunModeBIT.java b/src/test/java/org/apache/sling/crankstart/launcher/RunModeBIT.java
index c00e8f3..bad8b2f 100644
--- a/src/test/java/org/apache/sling/crankstart/launcher/RunModeBIT.java
+++ b/src/test/java/org/apache/sling/crankstart/launcher/RunModeBIT.java
@@ -26,7 +26,7 @@
public final RetryRule retryRule = new RetryRule();
@BeforeClass
- public static void setupClass() throws IOException {
+ public static void setupClass() throws Exception {
System.setProperty(RunModeFilter.SLING_RUN_MODES, RUN_MODES);
C.setup();
osgiConsole = new WebconsoleClient(C.getBaseUrl(), U.ADMIN, U.ADMIN);
diff --git a/src/test/resources/launchpad-addons.txt b/src/test/resources/launchpad-addons.txt
deleted file mode 100644
index d787f38..0000000
--- a/src/test/resources/launchpad-addons.txt
+++ /dev/null
@@ -1,55 +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.
-#
-
-# Additional items needed to be able to start the Sling Launchpad
-# using the :crankstart feature found in this folder + this file +
-# the standard model from launchpad/builder so that it passes
-# the Sling integration tests. As of June 11th, 2015 this is
-# not fully working, some integration tests fail. Probably due,
-# at least in part, to run modes not being implemented yet, which
-# means we possibly get conflicting bundles.
-#
-# Using this, currently 11 Sling tests from launchpad/integration-tests
-# fail, out of 528, when starting Sling with the following commands:
-# rm -rf CRANKSTART derby.log jackrabbit
-# java -Dcrankstart.model.http.port=8080 \
-# -Dsling.run.modes=:standalone,jackrabbit -jar \
-# target/org.apache.sling.crankstart.launcher-1.9.9-SNAPSHOT.jar \
-# src/test/resources/crankstart-model.txt \
-# src/test/resources/launchpad-addons.txt \
-# ../../..//launchpad/builder/src/main/provisioning
-
-[feature name=crankstart.launchpad.addons]
-
-[artifacts]
- org.apache.sling/org.apache.sling.launchpad.api/1.1.0
- org.apache.sling/org.apache.sling.launchpad.karaf/0.1.1-SNAPSHOT
- org.apache.sling/org.apache.sling.launchpad.test-services/2.0.9-SNAPSHOT
- org.apache.sling/org.apache.sling.junit.core/1.0.10
- org.apache.sling/org.apache.sling.junit.scriptable/1.0.10
- org.apache.sling/org.apache.sling.launchpad.test-fragment/2.0.9-SNAPSHOT
- org.apache.sling/org.apache.sling.servlets.compat/1.0.2
-
-[configurations]
- integrationTestsConfig
- message="This test config should be loaded at startup"
-
- org.apache.sling.servlets.resolver.SlingServletResolver
- # Set the servlet resolver's cache size to zero for testing
- servletresolver.cacheSize=I"0"
diff --git a/src/test/resources/provisioning-model/crankstart-tests.txt b/src/test/resources/provisioning-model/crankstart-tests.txt
index b43499e..a0a0dbd 100644
--- a/src/test/resources/provisioning-model/crankstart-tests.txt
+++ b/src/test/resources/provisioning-model/crankstart-tests.txt
@@ -24,6 +24,9 @@
org.apache.sling/org.apache.sling.junit.core/1.0.10
org.apache.sling/org.apache.sling.commons.mime/2.1.8
org.apache.sling/org.apache.sling.settings/1.3.6
+
+ # TODO: Test a nested model file
+ # org.apache.sling/org.apache.sling.launchpad/8-SNAPSHOT/slingstart
[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
new file mode 100644
index 0000000..936e735
--- /dev/null
+++ b/src/test/resources/sling-launchpad.txt
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+# Start the Sling Launchpad including whatever is required to
+# run the Sling integration tests.
+# This model is meant to be used in addition to the base
+# crankstart-model
+[feature name=sling.launchpad]
+
+[settings]
+ org.apache.sling.commons.log.julenabled=true
+
+[artifacts]
+ # karaf bunde provides Sling Launchpad startup services
+ org.apache.sling/org.apache.sling.launchpad.karaf/0.1.1-SNAPSHOT
+
+ # The launchpad itself
+ org.apache.sling/org.apache.sling.launchpad/8-SNAPSHOT/txt/slingfeature
+
+ # Sling integration tests support
+ org.apache.sling/org.apache.sling.launchpad.test-bundles/0.0.1-SNAPSHOT/txt/slingstart
+
+[configurations]
+ integrationTestsConfig
+ message="This test config should be loaded at startup"
+
+ org.apache.sling.servlets.resolver.SlingServletResolver
+ # Set the servlet resolver's cache size to zero for testing
+ servletresolver.cacheSize=I"0"
\ No newline at end of file