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() : "") + ")"); + } + }); } } }