You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by pa...@apache.org on 2018/06/21 11:26:11 UTC
[sling-org-apache-sling-feature-launcher] branch master updated:
Rework the framework launching to take into account restart requests,
add the launchpad.api, and take into account incremental install flag.
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 2994b09 Rework the framework launching to take into account restart requests, add the launchpad.api, and take into account incremental install flag.
2994b09 is described below
commit 2994b09538d18c4ffbeb71949037d6455b567c2b
Author: Karl Pauls <ka...@gmail.com>
AuthorDate: Thu Jun 21 13:26:02 2018 +0200
Rework the framework launching to take into account restart requests, add the launchpad.api, and take into account incremental install flag.
---
pom.xml | 6 ++
.../apache/sling/feature/launcher/impl/Main.java | 7 +-
.../launcher/impl/launchers/AbstractRunner.java | 112 ++++++++++++++++++++-
.../launcher/impl/launchers/FrameworkLauncher.java | 27 +++--
.../launcher/impl/launchers/FrameworkRunner.java | 30 +++++-
.../sling/feature/launcher/spi/Launcher.java | 2 +-
6 files changed, 167 insertions(+), 17 deletions(-)
diff --git a/pom.xml b/pom.xml
index 9e0db4e..9c5aabf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -131,6 +131,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.launchpad.api</artifactId>
+ <version>1.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.converter</artifactId>
<version>1.0.0</version>
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 39d6f40..8b990c5 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
@@ -38,6 +38,7 @@ import org.apache.sling.feature.io.ArtifactManager;
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;
+import org.osgi.framework.FrameworkEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -233,9 +234,9 @@ public class Main {
}
final Launcher launcher = new FrameworkLauncher();
- launcher.run(installation, createClassLoader(installation));
-
- config.clear();
+ while (launcher.run(installation, createClassLoader(installation)) == FrameworkEvent.STOPPED_SYSTEM_REFRESHED) {
+ Main.LOG().info("Framework restart due to extension refresh");
+ }
}
/**
diff --git a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/AbstractRunner.java b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/AbstractRunner.java
index 466297b..00ec9cb 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/AbstractRunner.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/AbstractRunner.java
@@ -17,13 +17,18 @@
package org.apache.sling.feature.launcher.impl.launchers;
import org.apache.sling.feature.launcher.impl.Main;
+import org.apache.sling.launchpad.api.StartupHandler;
+import org.apache.sling.launchpad.api.StartupMode;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@@ -41,11 +46,15 @@ import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Common functionality for the framework start.
*/
-public class AbstractRunner {
+public abstract class AbstractRunner implements Callable<Integer> {
private volatile ServiceTracker<Object, Object> configAdminTracker;
@@ -55,9 +64,22 @@ public class AbstractRunner {
private final List<File> installables;
- public AbstractRunner(final List<Object[]> configurations, final List<File> installables) {
+ private final int targetStartlevel;
+
+ private final AtomicInteger waitRequested = new AtomicInteger(0);
+
+ public AbstractRunner(final Map<String, String> frameworkProperties, final List<Object[]> configurations, final List<File> installables) {
this.configurations = new ArrayList<>(configurations);
this.installables = installables;
+ String target = frameworkProperties.get(Constants.FRAMEWORK_BEGINNING_STARTLEVEL);
+ if (target != null) {
+ targetStartlevel = Integer.parseInt(target);
+ } else {
+ targetStartlevel = 1;
+ }
+ if ("true".equalsIgnoreCase(frameworkProperties.get("sling.framework.install.incremental"))) {
+ frameworkProperties.put(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, "1");
+ }
}
protected void setupFramework(final Framework framework, final Map<Integer, List<File>> bundlesMap)
@@ -124,11 +146,97 @@ public class AbstractRunner {
});
this.installerTracker.open();
}
+
+ int bundleCount = framework.getBundleContext().getBundles().length;
+
try {
this.install(framework, bundlesMap);
} catch ( final IOException ioe) {
throw new BundleException("Unable to install bundles.", ioe);
}
+
+ try
+ {
+ // TODO: double check bundles and take installables into account
+ final StartupMode mode = framework.getBundleContext().getBundles().length == bundleCount ? StartupMode.RESTART :
+ bundleCount > 1 ? StartupMode.UPDATE : StartupMode.INSTALL;
+
+ framework.getBundleContext().registerService(StartupHandler.class, new StartupHandler()
+ {
+ @Override
+ public StartupMode getMode()
+ {
+ return mode;
+ }
+
+ @Override
+ public boolean isFinished() {
+ return framework.getState() == Framework.ACTIVE && targetStartlevel > framework.adapt(FrameworkStartLevel.class).getStartLevel();
+ }
+
+ @Override
+ public void waitWithStartup(boolean b) {
+ if (b) {
+ waitRequested.incrementAndGet();
+ }
+ else {
+ waitRequested.decrementAndGet();
+ }
+ }
+ }, null);
+ } catch (NoClassDefFoundError ex) {
+ // Ignore, we don't have the launchpad.api
+ }
+ }
+
+ protected boolean startFramework(final Framework framework, long timeout, TimeUnit unit) throws BundleException, InterruptedException
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+ FrameworkListener listener = new FrameworkListener()
+ {
+ @Override
+ public void frameworkEvent(FrameworkEvent frameworkEvent)
+ {
+ if (frameworkEvent.getType() == FrameworkEvent.STARTED || frameworkEvent.getType() == FrameworkEvent.STARTLEVEL_CHANGED) {
+ if (framework.getState() == Framework.ACTIVE && targetStartlevel > framework.adapt(FrameworkStartLevel.class).getStartLevel())
+ {
+ if (waitRequested.get() == 0) {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ while (waitRequested.get() > 0) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ framework.adapt(FrameworkStartLevel.class).setStartLevel(framework.adapt(FrameworkStartLevel.class).getStartLevel() + 1);
+ } catch (Exception ex) {
+ latch.countDown();
+ }
+ }
+ else {
+ latch.countDown();
+ }
+ }
+ }
+ };
+
+ framework.getBundleContext().addFrameworkListener(listener);
+
+ framework.start();
+
+ try {
+ return latch.await(timeout, unit);
+ } finally {
+ framework.getBundleContext().removeFrameworkListener(listener);
+ }
}
private void configure(final Object configAdmin) {
diff --git a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkLauncher.java b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkLauncher.java
index 12a5c66..d34221f 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkLauncher.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkLauncher.java
@@ -19,16 +19,20 @@ package org.apache.sling.feature.launcher.impl.launchers;
import org.apache.commons.lang.text.StrLookup;
import org.apache.commons.lang.text.StrSubstitutor;
import org.apache.sling.feature.Application;
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.launcher.impl.Main;
import org.apache.sling.feature.launcher.spi.Launcher;
import org.apache.sling.feature.launcher.spi.LauncherPrepareContext;
import org.apache.sling.feature.launcher.spi.LauncherRunContext;
+import org.osgi.framework.Constants;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
/**
* Launcher directly using the OSGi launcher API.
@@ -39,14 +43,23 @@ public class FrameworkLauncher implements Launcher {
@Override
public void prepare(final LauncherPrepareContext context, final Application app) throws Exception {
context.addAppJar(context.getArtifactFile(app.getFramework()));
+ ArtifactId api = ArtifactId.fromMvnId("org.apache.sling:org.apache.sling.launchpad.api:1.2.0");
+ Artifact artifact = app.getBundles().getSame(api);
+ if (artifact != null)
+ {
+ api = artifact.getId();
+ context.addAppJar(context.getArtifactFile(api));
+ app.getBundles().removeExact(api);
+ app.getFrameworkProperties().put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "org.apache.sling.launchpad.api;version=\"" + api.getOSGiVersion() + "\"");
+ }
}
/**
* Run the launcher
- * @throws If anything goes wrong
+ * @throws Exception If anything goes wrong
*/
@Override
- public void run(final LauncherRunContext context, final ClassLoader cl) throws Exception {
+ public int run(final LauncherRunContext context, final ClassLoader cl) throws Exception {
StrSubstitutor ss = new StrSubstitutor(new StrLookup() {
@Override
public String lookup(String key) {
@@ -62,7 +75,7 @@ public class FrameworkLauncher implements Launcher {
Map<String, String> properties = new HashMap<>();
context.getFrameworkProperties().forEach((key, value) -> {
- properties.put(key, ss.replace(value));
+ properties.put(key, ss.replace(value).replace("{dollar}", "$"));
});
if ( Main.LOG().isDebugEnabled() ) {
Main.LOG().debug("Bundles:");
@@ -86,18 +99,16 @@ public class FrameworkLauncher implements Launcher {
}
Main.LOG().debug("");
}
- long time = System.currentTimeMillis();
- final Class<?> runnerClass = cl.loadClass(this.getClass().getPackage().getName() + ".FrameworkRunner");
+ final Class<?> runnerClass = cl.loadClass(FrameworkRunner.class.getName());
final Constructor<?> constructor = runnerClass.getDeclaredConstructor(Map.class, Map.class, List.class, List.class);
constructor.setAccessible(true);
- constructor.newInstance(properties,
+ Callable<Integer> restart = (Callable<Integer>) constructor.newInstance(properties,
context.getBundleMap(),
context.getConfigurations(),
context.getInstallableArtifacts());
- Main.LOG().debug("Startup took: " + (System.currentTimeMillis() - time));
+ return restart.call();
// nothing else to do, constructor starts everything
- // TODO: wait for stop and restart framework when necessary
}
}
diff --git a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
index f17b6c3..25ce117 100644
--- a/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
+++ b/src/main/java/org/apache/sling/feature/launcher/impl/launchers/FrameworkRunner.java
@@ -26,17 +26,21 @@ import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Launcher directly using the OSGi launcher API.
*/
public class FrameworkRunner extends AbstractRunner {
+ private volatile int type = -1;
+
public FrameworkRunner(final Map<String, String> frameworkProperties,
final Map<Integer, List<File>> bundlesMap,
final List<Object[]> configurations,
final List<File> installables) throws Exception {
- super(configurations, installables);
+ super(frameworkProperties, configurations, installables);
final ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);
FrameworkFactory factory = null;
@@ -58,7 +62,7 @@ public class FrameworkRunner extends AbstractRunner {
public void run() {
try {
framework.stop();
- FrameworkEvent waitForStop = framework.waitForStop(10000);
+ FrameworkEvent waitForStop = framework.waitForStop(60 * 1000);
if (waitForStop.getType() != FrameworkEvent.STOPPED)
{
Main.LOG().warn("Framework stopped with: " + waitForStop.getType(), waitForStop.getThrowable());
@@ -76,7 +80,27 @@ public class FrameworkRunner extends AbstractRunner {
this.setupFramework(framework, bundlesMap);
+
+ long time = System.currentTimeMillis();
+
// finally start
- framework.start();
+ if (!this.startFramework(framework, 10, TimeUnit.MINUTES)) {
+ throw new TimeoutException("Waited for more than 10 minutes to startup framework.");
+ }
+
+ Main.LOG().debug("Startup took: " + (System.currentTimeMillis() - time));
+
+ while ((type = framework.waitForStop(Long.MAX_VALUE).getType()) == FrameworkEvent.STOPPED_UPDATE) {
+ Main.LOG().info("Framework restart due to update");
+ time = System.currentTimeMillis();
+ if (!this.startFramework(framework, 10, TimeUnit.MINUTES)) {
+ throw new TimeoutException("Waited for more than 10 minutes to startup framework.");
+ }
+ Main.LOG().debug("Restart took: " + (System.currentTimeMillis() - time));
+ }
+ }
+
+ public Integer call() {
+ return type;
}
}
diff --git a/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java b/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
index a1ced11..26819c4 100644
--- a/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
+++ b/src/main/java/org/apache/sling/feature/launcher/spi/Launcher.java
@@ -22,5 +22,5 @@ public interface Launcher {
void prepare(LauncherPrepareContext context, Application app) throws Exception;
- void run(LauncherRunContext context, ClassLoader cl) throws Exception;
+ int run(LauncherRunContext context, ClassLoader cl) throws Exception;
}