This is an automated email from the ASF dual-hosted git repository.
pauls pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-launcher.git
The following commit(s) were added to refs/heads/master by this push:
new e253419 Allow to specify several features to be launched.
e253419 is described below
commit e25341911ea0889c5be72cd99bce4e96555adf50
Author: Karl Pauls <[email protected]>
AuthorDate: Tue Aug 28 22:47:02 2018 +0200
Allow to specify several features to be launched.
---
pom.xml | 2 +
.../feature/launcher/impl/FeatureProcessor.java | 91 ++++++++-----
.../feature/launcher/impl/LauncherConfig.java | 26 +---
.../apache/sling/feature/launcher/impl/Main.java | 147 +++++++++++++--------
4 files changed, 155 insertions(+), 111 deletions(-)
diff --git a/pom.xml b/pom.xml
index 2062ac6..2fa5dd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,8 @@
<configuration>
<excludes>
<exclude>readme.md</exclude>
+
<exclude>src/main/resources/META-INF/services/**</exclude>
+ <exclude>**/*.properties</exclude>
</excludes>
</configuration>
</plugin>
diff --git
a/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
b/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
index 5c7a4ff..8fe6874 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
@@ -18,29 +18,36 @@ package org.apache.sling.feature.launcher.impl;
import java.io.File;
import java.io.FileReader;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
+import java.util.ServiceLoader;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonReader;
import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Configuration;
import org.apache.sling.feature.Extension;
import org.apache.sling.feature.ExtensionType;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.FeatureConstants;
-import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.builder.BuilderContext;
import org.apache.sling.feature.builder.FeatureBuilder;
+import org.apache.sling.feature.builder.FeatureExtensionHandler;
import org.apache.sling.feature.io.ArtifactHandler;
import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.IOUtils;
import org.apache.sling.feature.io.json.FeatureJSONReader;
-import org.apache.sling.feature.io.json.FeatureJSONWriter;
import org.apache.sling.feature.launcher.impl.LauncherConfig.StartupMode;
public class FeatureProcessor {
@@ -52,27 +59,50 @@ public class FeatureProcessor {
* @param artifactManager The artifact manager
*/
public static Feature createApplication(final LauncherConfig config,
- final ArtifactManager artifactManager)
- throws IOException {
- Feature app = null;
- if ( config.getApplicationFile() != null ) {
- app = read(config.getApplicationFile(), artifactManager,
config.getVariables());
- // write application back
- final File file = new File(config.getHomeDirectory(), "resources"
+ File.separatorChar + "provisioning" + File.separatorChar +
"application.json");
- file.getParentFile().mkdirs();
-
- try (final FileWriter writer = new FileWriter(file)) {
- FeatureJSONWriter.write(writer, app);
- } catch ( final IOException ioe) {
- Main.LOG().error("Error while writing application file: {}",
ioe.getMessage(), ioe);
- System.exit(1);
+ final ArtifactManager artifactManager) throws IOException
+ {
+
+ final BuilderContext builderContext = new BuilderContext(
+ id -> {
+ try {
+ final ArtifactHandler handler =
artifactManager.getArtifactHandler(id.toMvnUrl());
+ try (final FileReader r = new
FileReader(handler.getFile())) {
+ final Feature f = FeatureJSONReader.read(r,
handler.getUrl());
+ return f;
+ }
+
+ } catch (final IOException e) {
+ // ignore
+ }
+ return null;
+ }).add(StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ ServiceLoader.load(FeatureExtensionHandler.class).iterator(),
Spliterator.ORDERED), false).toArray(FeatureExtensionHandler[]::new));
+
+ List<Feature> features = new ArrayList<>();
+
+ for (final String initFile : config.getFeatureFiles())
+ {
+ try
+ {
+ final Feature f = IOUtils.getFeature(initFile,
artifactManager);
+ features.add(f);
+ }
+ catch (Exception ex)
+ {
+ throw new IOException("Error reading feature: " + initFile,
ex);
}
}
- else {
- app = read(new File(config.getHomeDirectory(), "resources" +
File.separatorChar + "provisioning" + File.separatorChar +
"application.json").getPath(),
- artifactManager, config.getVariables());
- }
+ Collections.sort(features);
+
+ // TODO make feature id configurable
+ final Feature app =
FeatureBuilder.assemble(ArtifactId.fromMvnId("group:assembled:1.0.0"),
builderContext, features.toArray(new Feature[0]));
+
+ final Artifact a = new
Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
+ a.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER,
"1");
+ app.getBundles().add(a);
+
+ // TODO: this sucks
for (Artifact bundle : app.getBundles()) {
if ( bundle.getStartOrder() == 0) {
final int so = bundle.getMetadata().get("start-level") != null
? Integer.parseInt(bundle.getMetadata().get("start-level")) : 1;
@@ -80,22 +110,11 @@ public class FeatureProcessor {
}
}
+ FeatureBuilder.resolveVariables(app, config.getVariables());
+
return app;
}
- private static Feature read(String absoluteArg, ArtifactManager
artifactManager,
- KeyValueMap overriddenVars) throws IOException {
- if ( absoluteArg.indexOf(":") < 2 ) {
- absoluteArg = new File(absoluteArg).getAbsolutePath();
- }
- final ArtifactHandler appArtifact =
artifactManager.getArtifactHandler(absoluteArg);
-
- try (final FileReader r = new FileReader(appArtifact.getFile())) {
- final Feature f = FeatureJSONReader.read(r, appArtifact.getUrl());
- FeatureBuilder.resolveVariables(f, overriddenVars);
- return f;
- }
- }
/**
* Prepare the launcher
* - add all bundles to the bundle map of the installation object
@@ -115,7 +134,7 @@ public class FeatureProcessor {
}
int index = 1;
for(final Extension ext : app.getExtensions()) {
- if ( ext.getType() == ExtensionType.ARTIFACTS ) {
+ if ( ext.getType() == ExtensionType.ARTIFACTS &&
!ext.getName().equals(FeatureConstants.EXTENSION_NAME_ASSEMBLED_FEATURES)) {
for(final Artifact a : ext.getArtifacts() ) {
if ( config.getStartupMode() == StartupMode.PURE ) {
throw new Exception("Artifacts other than bundle are
not supported by framework launcher.");
diff --git
a/src/main/java/org/apache/sling/feature/launcher/impl/LauncherConfig.java
b/src/main/java/org/apache/sling/feature/launcher/impl/LauncherConfig.java
index 191ecb6..a6272a2 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/LauncherConfig.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/LauncherConfig.java
@@ -18,6 +18,8 @@ package org.apache.sling.feature.launcher.impl;
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
import org.apache.sling.feature.KeyValueMap;
import org.apache.sling.feature.io.ArtifactManagerConfig;
@@ -40,10 +42,7 @@ public class LauncherConfig
private static final String CACHE_DIR = "cache";
/** The feature files or directories. */
- private volatile String[] featureFiles;
-
- /** The application file. */
- private volatile String appFile;
+ private final LinkedHashSet<String> featureFiles = new LinkedHashSet<>();
private volatile StartupMode startupMode = StartupMode.PURE;
@@ -61,23 +60,12 @@ public class LauncherConfig
this.setCacheDirectory(new File(getHomeDirectory(), CACHE_DIR));
}
- public void setApplicationFile(final String value) {
- appFile = value;
- }
-
- public String getApplicationFile() {
- return this.appFile;
- }
-
/**
* Set the list of feature files or directories.
- * @param value The array with the feature file names.
+ * @param featureFiles The array with the feature file names.
*/
- public void setFeatureFiles(final String[] value) {
- this.featureFiles = value;
- if ( value != null && value.length == 0 ) {
- this.featureFiles = null;
- }
+ public void addFeatureFiles(final String... featureFiles) {
+ this.featureFiles.addAll(Arrays.asList(featureFiles));
}
/**
@@ -86,7 +74,7 @@ public class LauncherConfig
* @throws IOException
*/
public String[] getFeatureFiles() {
- return this.featureFiles;
+ return this.featureFiles.toArray(new String[0]);
}
diff --git a/src/main/java/org/apache/sling/feature/launcher/impl/Main.java
b/src/main/java/org/apache/sling/feature/launcher/impl/Main.java
index eb657e0..5a2f335 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/Main.java
@@ -17,7 +17,9 @@
package org.apache.sling.feature.launcher.impl;
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
@@ -39,6 +41,7 @@ import org.apache.sling.feature.Feature;
import org.apache.sling.feature.io.ArtifactHandler;
import org.apache.sling.feature.io.ArtifactManager;
import org.apache.sling.feature.io.IOUtils;
+import org.apache.sling.feature.io.json.FeatureJSONWriter;
import org.apache.sling.feature.launcher.impl.launchers.FrameworkLauncher;
import org.apache.sling.feature.launcher.spi.Launcher;
import org.apache.sling.feature.launcher.spi.LauncherPrepareContext;
@@ -83,7 +86,7 @@ public class Main {
final Options options = new Options();
final Option repoOption = new Option("u", true, "Set repository url");
- final Option appOption = new Option("a", true, "Set application
file");
+ final Option featureOption = new Option("f", true, "Set feature
files");
final Option fwkProperties = new Option("D", true, "Set framework
properties");
final Option varValue = new Option("V", true, "Set variable value");
final Option debugOption = new Option("v", false, "Verbose");
@@ -97,7 +100,7 @@ public class Main {
final Option frameworkOption = new Option("fv", true, "Set felix
framework version");
options.addOption(repoOption);
- options.addOption(appOption);
+ options.addOption(featureOption);
options.addOption(fwkProperties);
options.addOption(varValue);
options.addOption(debugOption);
@@ -135,8 +138,10 @@ public class Main {
if ( cl.hasOption(installerOption.getOpt()) ) {
config.setUseInstaller();
}
- if ( cl.hasOption(appOption.getOpt()) ) {
-
config.setApplicationFile(cl.getOptionValue(appOption.getOpt()));
+ if ( cl.hasOption(featureOption.getOpt()) ) {
+ for(final String optVal :
cl.getOptionValues(featureOption.getOpt())) {
+ config.addFeatureFiles(optVal.split(","));
+ }
}
if (cl.hasOption(cacheOption.getOpt())) {
config.setCacheDirectory(new
File(cl.getOptionValue(cacheOption.getOpt())));
@@ -185,53 +190,44 @@ public class Main {
Main.LOG().info("Apache Sling Application Launcher");
Main.LOG().info("---------------------------------");
- ArtifactManager artifactManager = null;
- try {
- Main.LOG().info("Initializing...");
- try {
- artifactManager =
ArtifactManager.getArtifactManager(launcherConfig);
- } catch ( final IOException ioe) {
- Main.LOG().error("Unable to setup artifact manager: {}",
ioe.getMessage(), ioe);
- System.exit(1);
- }
+ Main.LOG().info("Initializing...");
+
+ final Launcher launcher = new FrameworkLauncher();
+
+ try (ArtifactManager artifactManager =
ArtifactManager.getArtifactManager(launcherConfig)) {
+
Main.LOG().info("Artifact Repositories: {}",
Arrays.toString(launcherConfig.getRepositoryUrls()));
Main.LOG().info("Assembling provisioning model...");
try {
- final Launcher launcher = new FrameworkLauncher();
- final Feature app =
FeatureProcessor.createApplication(launcherConfig, artifactManager);
+ boolean restart = launcherConfig.getFeatureFiles().length == 0;
+
+ final Feature app = assemble(launcherConfig, artifactManager);
Main.LOG().info("");
Main.LOG().info("Assembling launcher...");
- final ArtifactManager aMgr = artifactManager;
- final LauncherPrepareContext ctx = new
LauncherPrepareContext() {
+ final LauncherPrepareContext ctx = new LauncherPrepareContext()
+ {
@Override
- public File getArtifactFile(final ArtifactId artifact)
throws IOException {
- final ArtifactHandler handler =
aMgr.getArtifactHandler(":" + artifact.toMvnPath());
- if (m_populate != null) {
- File source = handler.getFile();
- File target = new File(m_populate,
artifact.toMvnPath().replace('/', File.separatorChar));
-
- if (!target.isFile()) {
- if (Main.LOG().isDebugEnabled()) {
- Main.LOG().debug("Populating {} with {}",
target.getAbsolutePath(), source.getAbsolutePath());
- }
- target.getParentFile().mkdirs();
- Files.copy(source.toPath(), target.toPath());
- }
+ public File getArtifactFile(final ArtifactId artifact)
throws IOException
+ {
+ final ArtifactHandler handler =
artifactManager.getArtifactHandler(":" + artifact.toMvnPath());
+ if (m_populate != null)
+ {
+ populate(handler.getFile(), artifact);
}
return handler.getFile();
}
@Override
- public void addAppJar(final File jar) {
+ public void addAppJar(final File jar)
+ {
launcherConfig.getInstallation().addAppJar(jar);
}
};
- // use hard coded Apache Felix
launcher.prepare(ctx,
IOUtils.getFelixFrameworkId(m_frameworkVersion), app);
FeatureProcessor.prepareLauncher(launcherConfig,
artifactManager, app);
@@ -239,46 +235,86 @@ public class Main {
Main.LOG().info("Using {} local artifacts, {} cached
artifacts, and {} downloaded artifacts",
launcherConfig.getLocalArtifacts(),
launcherConfig.getCachedArtifacts(), launcherConfig.getDownloadedArtifacts());
- if (m_populate != null) {
+ if (m_populate != null)
+ {
Map<Artifact, File> local =
FeatureProcessor.calculateArtifacts(artifactManager, app);
- for (Map.Entry<Artifact, File> entry : local.entrySet()) {
- File source = entry.getValue();
- File target = new File(m_populate,
entry.getKey().getId().toMvnPath().replace('/', File.separatorChar));
-
- if (!target.isFile()) {
- if (Main.LOG().isDebugEnabled()) {
- Main.LOG().debug("Populating {} with {}",
target.getAbsolutePath(), source.getAbsolutePath());
- }
- target.getParentFile().mkdirs();
- Files.copy(source.toPath(), target.toPath());
- }
+ for (Map.Entry<Artifact, File> entry : local.entrySet())
+ {
+ populate(entry.getValue(), entry.getKey().getId());
}
return;
}
+ if (restart) {
+
launcherConfig.getInstallation().getInstallableArtifacts().clear();
+
launcherConfig.getInstallation().getConfigurations().clear();
+ launcherConfig.getInstallation().getBundleMap().clear();
+ }
} catch ( final Exception iae) {
Main.LOG().error("Error while assembling launcher: {}",
iae.getMessage(), iae);
System.exit(1);
}
- } finally {
- if ( artifactManager != null ) {
- artifactManager.shutdown();
- }
}
-
- if (launcherConfig.getApplicationFile() == null) {
- launcherConfig.getInstallation().getBundleMap().clear();
- launcherConfig.getInstallation().getConfigurations().clear();
- launcherConfig.getInstallation().getInstallableArtifacts().clear();
+ catch (IOException ex) {
+ Main.LOG().error("Unable to setup artifact manager: {}",
ex.getMessage(), ex);
+ System.exit(1);
}
+
try {
- run(launcherConfig);
+ run(launcherConfig, launcher);
} catch ( final Exception iae) {
Main.LOG().error("Error while running launcher: {}",
iae.getMessage(), iae);
System.exit(1);
}
}
+ private static void populate(File file, ArtifactId artifactId) throws
IOException{
+ File target = new File(m_populate, artifactId.toMvnPath().replace('/',
File.separatorChar));
+
+ if (!target.isFile())
+ {
+ if (Main.LOG().isDebugEnabled())
+ {
+ Main.LOG().debug("Populating {} with {}",
target.getAbsolutePath(), file.getAbsolutePath());
+ }
+ target.getParentFile().mkdirs();
+ Files.copy(file.toPath(), target.toPath());
+ }
+ }
+
+ private static Feature assemble(final LauncherConfig launcherConfig, final
ArtifactManager artifactManager) throws IOException
+ {
+ if (launcherConfig.getFeatureFiles().length == 0) {
+ File application = new File(launcherConfig.getHomeDirectory(),
"resources" + File.separatorChar + "provisioning" + File.separatorChar +
"application.json");
+ if (application.isFile()) {
+
launcherConfig.addFeatureFiles(application.toURI().toURL().toString());
+ }
+ else {
+ throw new IllegalStateException("No feature(s) to launch found
and none where specified");
+ }
+ return FeatureProcessor.createApplication(launcherConfig,
artifactManager);
+ }
+ else
+ {
+ final Feature app =
FeatureProcessor.createApplication(launcherConfig, artifactManager);
+
+ // write application back
+ final File file = new File(launcherConfig.getHomeDirectory(),
"resources" + File.separatorChar + "provisioning" + File.separatorChar +
"application.json");
+ file.getParentFile().mkdirs();
+
+ try (final FileWriter writer = new FileWriter(file))
+ {
+ FeatureJSONWriter.write(writer, app);
+ }
+ catch (final IOException ioe)
+ {
+ Main.LOG().error("Error while writing application file: {}",
ioe.getMessage(), ioe);
+ System.exit(1);
+ }
+ return app;
+ }
+ }
+
private static final String STORAGE_PROPERTY =
"org.osgi.framework.storage";
private static final String START_LEVEL_PROP =
"org.osgi.framework.startlevel.beginning";
@@ -288,7 +324,7 @@ public class Main {
* @param config The configuration
* @throws Exception If anything goes wrong
*/
- private static void run(final LauncherConfig config) throws Exception {
+ private static void run(final LauncherConfig config, final Launcher
launcher) throws Exception {
Main.LOG().info("");
Main.LOG().info("Starting launcher...");
Main.LOG().info("Launcher Home: {}",
config.getHomeDirectory().getAbsolutePath());
@@ -317,7 +353,6 @@ public class Main {
installation.getFrameworkProperties().put(START_LEVEL_PROP, "30");
}
- final Launcher launcher = new FrameworkLauncher();
while (launcher.run(installation, createClassLoader(installation)) ==
FrameworkEvent.STOPPED_SYSTEM_REFRESHED) {
Main.LOG().info("Framework restart due to extension refresh");
}