From fea02c7de1b2bcce3be5138b81af78e1e5f49036 Mon Sep 17 00:00:00 2001
From: Piotr Skowronek
Date: Sun, 17 Sep 2023 18:55:46 +0200
Subject: [PATCH] AutoProcessor - Load and start bundles in parallel
---
.../org/apache/felix/main/AutoProcessor.java | 136 +++++++++++-------
1 file changed, 87 insertions(+), 49 deletions(-)
diff --git a/main/src/main/java/org/apache/felix/main/AutoProcessor.java b/main/src/main/java/org/apache/felix/main/AutoProcessor.java
index 6c00972a2b..94e36d196d 100644
--- a/main/src/main/java/org/apache/felix/main/AutoProcessor.java
+++ b/main/src/main/java/org/apache/felix/main/AutoProcessor.java
@@ -20,6 +20,12 @@
import java.io.File;
import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
import org.osgi.framework.*;
import org.osgi.service.startlevel.*;
@@ -89,9 +95,17 @@ public class AutoProcessor
**/
public static void process(Map configMap, BundleContext context)
{
- configMap = (configMap == null) ? new HashMap() : configMap;
- processAutoDeploy(configMap, context);
- processAutoProperties(configMap, context);
+ ExecutorService executor = null;
+ try {
+ executor = Executors.newFixedThreadPool(8);
+ Map configMapLocal = (configMap == null) ? new HashMap() : configMap;
+ processAutoDeploy(executor, configMapLocal, context);
+ processAutoProperties(executor, configMapLocal, context);
+ } finally {
+ if (executor != null) {
+ executor.shutdown();
+ }
+ }
}
/**
@@ -100,7 +114,8 @@ public static void process(Map configMap, BundleContext context)
* specified deploy actions.
*
*/
- private static void processAutoDeploy(Map configMap, BundleContext context)
+ private static void processAutoDeploy(ExecutorService executor, Map configMap,
+ BundleContext context)
{
// Determine if auto deploy actions to perform.
String action = (String) configMap.get(AUTO_DEPLOY_ACTION_PROPERTY);
@@ -156,28 +171,28 @@ private static void processAutoDeploy(Map configMap, BundleContext context)
// Look in the specified bundle directory to create a list
// of all JAR files to install.
File[] files = new File(autoDir).listFiles();
- List jarList = new ArrayList();
+ List jarList = new ArrayList<>();
if (files != null)
{
Arrays.sort(files);
- for (int i = 0; i < files.length; i++)
+ for (File file : files)
{
- if (files[i].getName().endsWith(".jar"))
+ if (file.getName().endsWith(".jar"))
{
- jarList.add(files[i]);
+ jarList.add(file);
}
}
}
// Install bundle JAR files and remember the bundle objects.
- final List startBundleList = new ArrayList();
- for (int i = 0; i < jarList.size(); i++)
+ final List> startBundleList = new ArrayList<>();
+ for (File jarFile : jarList)
{
// Look up the bundle by location, removing it from
// the map of installed bundles so the remaining bundles
// indicate which bundles may need to be uninstalled.
- Bundle b = (Bundle) installedBundleMap.remove(
- ((File) jarList.get(i)).toURI().toString());
+ Bundle b = (Bundle) installedBundleMap.remove(jarFile.toURI().toString());
+ Future futureBundle = CompletableFuture.completedFuture(b);
try
{
@@ -185,8 +200,18 @@ private static void processAutoDeploy(Map configMap, BundleContext context)
// if the 'install' action is present.
if ((b == null) && actionList.contains(AUTO_DEPLOY_INSTALL_VALUE))
{
- b = context.installBundle(
- ((File) jarList.get(i)).toURI().toString());
+ String jarPath = jarFile.toURI().toString();
+ b = context.installBundle(jarFile.toURI().toString());
+ futureBundle = executor.submit(() -> {
+ try {
+ return context.installBundle(jarPath);
+ } catch (BundleException ex) {
+ System.err.println("Auto-deploy install: "
+ + ex + ((ex.getCause() != null) ? " - "
+ + ex.getCause() : ""));
+ return null;
+ }
+ });
}
// If the bundle is already installed, then update it
// if the 'update' action is present.
@@ -194,15 +219,9 @@ else if ((b != null) && actionList.contains(AUTO_DEPLOY_UPDATE_VALUE))
{
b.update();
}
-
// If we have found and/or successfully installed a bundle,
// then add it to the list of bundles to potentially start
- // and also set its start level accordingly.
- if ((b != null) && !isFragment(b))
- {
- startBundleList.add(b);
- sl.setBundleStartLevel(b, startLevel);
- }
+ startBundleList.add(futureBundle);
}
catch (BundleException ex)
{
@@ -238,16 +257,31 @@ else if ((b != null) && actionList.contains(AUTO_DEPLOY_UPDATE_VALUE))
// action is present.
if (actionList.contains(AUTO_DEPLOY_START_VALUE))
{
- for (int i = 0; i < startBundleList.size(); i++)
+ for (Future bundleFuture : startBundleList)
{
- try
- {
- ((Bundle) startBundleList.get(i)).start();
- }
- catch (BundleException ex)
- {
- System.err.println("Auto-deploy start: "
- + ex + ((ex.getCause() != null) ? " - " + ex.getCause() : ""));
+ try {
+ Bundle bundle = bundleFuture.get();
+ int startLvl = startLevel;
+ executor.execute(() -> {
+ try
+ {
+ if (bundle != null) {
+ if (!isFragment(bundle)) {
+ // set its start level accordingly.
+ sl.setBundleStartLevel(bundle, startLvl);
+ bundle.start();
+ }
+ }
+ }
+ catch (BundleException ex)
+ {
+ System.err.println("Auto-deploy start: "
+ + ex + ((ex.getCause() != null) ? " - "
+ + ex.getCause() : ""));
+ }
+ });
+ } catch (InterruptedException | ExecutionException e) {
+ System.err.println("Problem getting bundle: " + e.getMessage());
}
}
}
@@ -260,7 +294,8 @@ else if ((b != null) && actionList.contains(AUTO_DEPLOY_UPDATE_VALUE))
* specified configuration properties.
*
*/
- private static void processAutoProperties(Map configMap, BundleContext context)
+ private static void processAutoProperties(ExecutorService executor,
+ Map configMap, BundleContext context)
{
// Retrieve the Start Level service, since it will be needed
// to set the start level of the installed bundles.
@@ -276,9 +311,9 @@ private static void processAutoProperties(Map configMap, BundleContext context)
// property name, where "n" is the desired start level for the list
// of bundles. If no start level is specified, the default start
// level is assumed.
- for (Iterator i = configMap.keySet().iterator(); i.hasNext(); )
+ for (Object keyObj : configMap.keySet())
{
- String key = ((String) i.next()).toLowerCase();
+ String key = ((String) keyObj).toLowerCase();
// Ignore all keys that are not an auto property.
if (!key.startsWith(AUTO_INSTALL_PROP) && !key.startsWith(AUTO_START_PROP))
@@ -315,35 +350,38 @@ private static void processAutoProperties(Map configMap, BundleContext context)
{
System.err.println("Auto-properties install: " + location + " ("
+ ex + ((ex.getCause() != null) ? " - " + ex.getCause() : "") + ")");
-if (ex.getCause() != null)
- ex.printStackTrace();
+ if (ex.getCause() != null)
+ ex.printStackTrace();
}
}
}
// Now loop through the auto-start bundles and start them.
- for (Iterator i = configMap.keySet().iterator(); i.hasNext(); )
+ for (Object keyObj : configMap.keySet())
{
- String key = ((String) i.next()).toLowerCase();
+ String key = ((String)keyObj).toLowerCase();
if (key.startsWith(AUTO_START_PROP))
{
StringTokenizer st = new StringTokenizer((String) configMap.get(key), "\" ", true);
for (String location = nextLocation(st); location != null; location = nextLocation(st))
{
- // Installing twice just returns the same bundle.
- try
- {
- Bundle b = context.installBundle(location, null);
- if (b != null)
+ String loc = location;
+ executor.execute(() -> {
+ try
{
- b.start();
+ // Installing twice just returns the same bundle.
+ Bundle b = context.installBundle(loc, null);
+ if (b != null)
+ {
+ b.start();
+ }
}
- }
- catch (Exception ex)
- {
- System.err.println("Auto-properties start: " + location + " ("
- + ex + ((ex.getCause() != null) ? " - " + ex.getCause() : "") + ")");
- }
+ catch (Exception ex)
+ {
+ System.err.println("Auto-properties start: " + loc + " ("
+ + ex + ((ex.getCause() != null) ? " - " + ex.getCause() : "") + ")");
+ }
+ });
}
}
}