X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Finit%2Fosgi%2FOsgiBoot.java;h=81efa33e33c8478eafbeeab09abde4ebd471f74e;hb=a46d57701e2fd1fbccbad801fab07331bc0b8502;hp=353e39c798ed2e69c23852a46dc6a49f474ab717;hpb=4f53d33d6a65a123ab8f69b8580de1da2e029a0a;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java index 353e39c79..81efa33e3 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java +++ b/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java @@ -4,8 +4,6 @@ import static org.argeo.init.osgi.OsgiBootUtils.debug; import static org.argeo.init.osgi.OsgiBootUtils.warn; import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -21,6 +19,9 @@ import java.util.Set; import java.util.SortedMap; import java.util.StringTokenizer; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; import org.argeo.init.a2.A2Source; import org.argeo.init.a2.ProvisioningManager; @@ -40,53 +41,45 @@ import org.osgi.framework.wiring.FrameworkWiring; */ public class OsgiBoot implements OsgiBootConstants { public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start"; + public final static String PROP_ARGEO_OSGI_MAX_START_LEVEL = "argeo.osgi.maxStartLevel"; public final static String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources"; - public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles"; - public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl"; - public final static String PROP_ARGEO_OSGI_LOCAL_CACHE = "argeo.osgi.localCache"; - public final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL = "argeo.osgi.distributionUrl"; + @Deprecated + final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles"; + final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl"; + final static String PROP_ARGEO_OSGI_LOCAL_CACHE = "argeo.osgi.localCache"; + final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL = "argeo.osgi.distributionUrl"; // booleans - public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug"; - // public final static String PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN = - // "argeo.osgi.boot.excludeSvn"; + @Deprecated + final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug"; - public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE = "argeo.osgi.boot.systemPropertiesFile"; - public final static String PROP_ARGEO_OSGI_BOOT_APPCLASS = "argeo.osgi.boot.appclass"; - public final static String PROP_ARGEO_OSGI_BOOT_APPARGS = "argeo.osgi.boot.appargs"; + final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE = "argeo.osgi.boot.systemPropertiesFile"; + final static String PROP_ARGEO_OSGI_BOOT_APPCLASS = "argeo.osgi.boot.appclass"; + final static String PROP_ARGEO_OSGI_BOOT_APPARGS = "argeo.osgi.boot.appargs"; + @Deprecated public final static String DEFAULT_BASE_URL = "reference:file:"; - // public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**"; + final static String DEFAULT_MAX_START_LEVEL = "32"; // OSGi standard properties final static String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL = "osgi.bundles.defaultStartLevel"; final static String PROP_OSGI_STARTLEVEL = "osgi.startLevel"; - final static String PROP_OSGI_INSTANCE_AREA = "osgi.instance.area"; - final static String PROP_OSGI_CONFIGURATION_AREA = "osgi.configuration.area"; - final static String PROP_OSGI_USE_SYSTEM_PROPERTIES = "osgi.framework.useSystemProperties"; + public final static String PROP_OSGI_INSTANCE_AREA = "osgi.instance.area"; + public final static String PROP_OSGI_CONFIGURATION_AREA = "osgi.configuration.area"; + public final static String PROP_OSGI_SHARED_CONFIGURATION_AREA = "osgi.sharedConfiguration.area"; + public final static String PROP_OSGI_USE_SYSTEM_PROPERTIES = "osgi.framework.useSystemProperties"; // Symbolic names - public final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.osgi.boot"; - public final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi"; - - /** Exclude svn metadata implicitely(a bit costly) */ - // private boolean excludeSvn = - // Boolean.valueOf(System.getProperty(PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN, - // "false")) - // .booleanValue(); - -// /** Default is 10s */ -// @Deprecated -// private long defaultTimeout = 10000l; + final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.init"; + final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi"; private final BundleContext bundleContext; private final String localCache; - private final ProvisioningManager provisioningManager; /* - * INITIALIZATION + * INITIALISATION */ /** Constructor */ public OsgiBoot(BundleContext bundleContext) { @@ -100,20 +93,29 @@ public class OsgiBoot implements OsgiBootConstants { if (sources == null) { provisioningManager.registerDefaultSource(); } else { +// OsgiBootUtils.debug("Found sources " + sources); for (String source : sources.split(",")) { + int qmIndex = source.lastIndexOf('?'); + String queryPart = ""; + if (qmIndex >= 0) { + queryPart = source.substring(qmIndex); + source = source.substring(0, qmIndex); + } if (source.trim().equals(A2Source.DEFAULT_A2_URI)) { - int qmIndex = source.lastIndexOf('?'); - String queryPart = ""; - if (qmIndex >= 0) { - queryPart = source.substring(qmIndex); - } if (Files.exists(homePath)) provisioningManager.registerSource( A2Source.SCHEME_A2 + "://" + homePath.toString() + "/.local/share/a2" + queryPart); provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/local/share/a2" + queryPart); provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/share/a2" + queryPart); + } else if (source.trim().equals(A2Source.DEFAULT_A2_REFERENCE_URI)) { + if (Files.exists(homePath)) + provisioningManager.registerSource(A2Source.SCHEME_A2_REFERENCE + "://" + homePath.toString() + + "/.local/share/a2" + queryPart); + provisioningManager + .registerSource(A2Source.SCHEME_A2_REFERENCE + ":///usr/local/share/a2" + queryPart); + provisioningManager.registerSource(A2Source.SCHEME_A2_REFERENCE + ":///usr/share/a2" + queryPart); } else { - provisioningManager.registerSource(source); + provisioningManager.registerSource(source + queryPart); } } } @@ -134,47 +136,34 @@ public class OsgiBoot implements OsgiBootConstants { public void bootstrap(Map properties) { try { long begin = System.currentTimeMillis(); - // check properties - if (properties != null) { - for (String property : properties.keySet()) { - String value = properties.get(property); - String bcValue = bundleContext.getProperty(property); - if (PROP_OSGI_CONFIGURATION_AREA.equals(property) || PROP_OSGI_INSTANCE_AREA.equals(property)) { - try { - URL uri = new URL(value); - URL bcUri = new URL(bcValue); - if (!uri.equals(bcUri)) - throw new IllegalArgumentException("Property " + property + "=" + uri - + " is inconsistent with bundle context : " + bcUri); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("Malformed property " + property, e); - } - - } else { - if (!value.equals(bcValue)) - throw new IllegalArgumentException("Property " + property + "=" + value - + " is inconsistent with bundle context : " + bcValue); - } - } - } else { - String useSystemProperties = bundleContext.getProperty(PROP_OSGI_USE_SYSTEM_PROPERTIES); - if (useSystemProperties == null || !useSystemProperties.equals("true")) { - OsgiBootUtils.warn("No properties passed but " + PROP_OSGI_USE_SYSTEM_PROPERTIES + " is not set."); - } - } // notify start - System.out.println(); - String osgiInstancePath = bundleContext.getProperty(PROP_OSGI_INSTANCE_AREA); - OsgiBootUtils - .info("OSGi bootstrap starting" + (osgiInstancePath != null ? " (" + osgiInstancePath + ")" : "")); + String osgiInstancePath = getProperty(PROP_OSGI_INSTANCE_AREA); + String osgiConfigurationPath = getProperty(PROP_OSGI_CONFIGURATION_AREA); + String osgiSharedConfigurationPath = getProperty(PROP_OSGI_CONFIGURATION_AREA); + OsgiBootUtils.info("OSGi bootstrap starting" // + + (osgiInstancePath != null ? " data: " + osgiInstancePath + "" : "") // + + (osgiConfigurationPath != null ? " state: " + osgiConfigurationPath + "" : "") // + + (osgiSharedConfigurationPath != null ? " config: " + osgiSharedConfigurationPath + "" : "") // + ); + + // legacy install bundles installUrls(getBundlesUrls()); installUrls(getDistributionUrls()); + + // A2 install bundles provisioningManager.install(null); - if (properties != null) - startBundles(properties); - else - startBundles(); + + // Make sure fragments are properly considered by refreshing + refreshFramework(); + + // start bundles +// if (properties != null && !Boolean.parseBoolean(properties.get(PROP_OSGI_USE_SYSTEM_PROPERTIES))) + startBundles(properties); +// else +// startBundles(); + + // complete long duration = System.currentTimeMillis() - begin; OsgiBootUtils.info("OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s (" + duration + "ms), " + bundleContext.getBundles().length + " bundles"); @@ -236,7 +225,7 @@ public class OsgiBoot implements OsgiBootConstants { String url = (String) urls.get(i); installUrl(url, installedBundles); } - refreshFramework(); +// refreshFramework(); } /** Actually install the provided URL */ @@ -313,39 +302,73 @@ public class OsgiBoot implements OsgiBootConstants { /* * START */ - /** - * Start bundles based on system properties. - * - * @see OsgiBoot#startBundles(Map) - */ - public void startBundles() { - Properties properties = System.getProperties(); - startBundles(properties); - } /** * Start bundles based on these properties. * - * @see OsgiBoot#startBundles(Map) + * @see OsgiBoot#doStartBundles(Map) */ + public void startBundles(Map properties) { + Map map = new TreeMap<>(); + // first use properties + if (properties != null) { + for (String key : properties.keySet()) { + String property = key; + if (property.startsWith(PROP_ARGEO_OSGI_START)) { + map.put(property, properties.get(property)); + } + } + } + // then try all start level until a maximum + int maxStartLevel = Integer.parseInt(getProperty(PROP_ARGEO_OSGI_MAX_START_LEVEL, DEFAULT_MAX_START_LEVEL)); + for (int i = 1; i <= maxStartLevel; i++) { + String key = PROP_ARGEO_OSGI_START + "." + i; + String value = getProperty(key); + if (value != null) + map.put(key, value); + + } + // finally, override with system properties + for (Object key : System.getProperties().keySet()) { + if (key.toString().startsWith(PROP_ARGEO_OSGI_START)) { + map.put(key.toString(), System.getProperty(key.toString())); + } + } + // start + doStartBundles(map); + } + + @Deprecated public void startBundles(Properties properties) { Map map = new TreeMap<>(); - for (Object key : properties.keySet()) { - String property = key.toString(); - if (property.startsWith(PROP_ARGEO_OSGI_START)) { - map.put(property, properties.getProperty(property)); + // first use properties + if (properties != null) { + for (Object key : properties.keySet()) { + String property = key.toString(); + if (property.startsWith(PROP_ARGEO_OSGI_START)) { + map.put(property, properties.get(property).toString()); + } } } startBundles(map); } /** Start bundle based on keys starting with {@link #PROP_ARGEO_OSGI_START}. */ - public void startBundles(Map properties) { + protected void doStartBundles(Map properties) { FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class); // default and active start levels from System properties - Integer defaultStartLevel = Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4")); - Integer activeStartLevel = Integer.parseInt(getProperty(PROP_OSGI_STARTLEVEL, "6")); + int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel(); + int defaultStartLevel = Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4")); + int activeStartLevel = Integer.parseInt(getProperty(PROP_OSGI_STARTLEVEL, "6")); + if (OsgiBootUtils.isDebug()) { + OsgiBootUtils.debug("OSGi default start level: " + + getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "") + ", using " + defaultStartLevel); + OsgiBootUtils.debug("OSGi active start level: " + getProperty(PROP_OSGI_STARTLEVEL, "") + + ", using " + activeStartLevel); + OsgiBootUtils.debug("Framework start level: " + frameworkStartLevel.getStartLevel() + " (initial: " + + initialStartLevel + ")"); + } SortedMap> startLevels = new TreeMap>(); computeStartLevels(startLevels, properties, defaultStartLevel); @@ -372,13 +395,32 @@ public class OsgiBoot implements OsgiBootConstants { } } } - frameworkStartLevel.setStartLevel(activeStartLevel, (FrameworkEvent event) -> { + + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.debug("About to set framework start level to " + activeStartLevel + " ..."); + + // Start the framework level after level + stages: for (int stage = initialStartLevel; stage <= activeStartLevel; stage++) { if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Framework event: " + event); - int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel(); - int startLevel = frameworkStartLevel.getStartLevel(); - OsgiBootUtils.debug("Framework start level: " + startLevel + " (initial: " + initialStartLevel + ")"); - }); + OsgiBootUtils.debug("Starting stage " + stage + "..."); + final int nextStage = stage; + final CompletableFuture stageCompleted = new CompletableFuture<>(); + ForkJoinPool.commonPool().execute(() -> { + frameworkStartLevel.setStartLevel(nextStage, (FrameworkEvent event) -> { + stageCompleted.complete(event); + }); + }); + FrameworkEvent event; + try { + event = stageCompleted.get(); + } catch (InterruptedException | ExecutionException e) { + throw new IllegalStateException("Cannot continue start", e); + } + if (event.getThrowable() != null) { + OsgiBootUtils.error("Stage " + nextStage + " failed, aborting start.", event.getThrowable()); + break stages; + } + } } private static void computeStartLevels(SortedMap> startLevels, Map properties, @@ -428,109 +470,6 @@ public class OsgiBoot implements OsgiBootConstants { } } -// /** -// * Start the provided list of bundles -// * -// * @return whether all bundles are now in active state -// * @deprecated -// */ -// @Deprecated -// public boolean startBundles(List bundlesToStart) { -// if (bundlesToStart.size() == 0) -// return true; -// -// // used to monitor ACTIVE states -// List startedBundles = new ArrayList(); -// // used to log the bundles not found -// List notFoundBundles = new ArrayList(bundlesToStart); -// -// Bundle[] bundles = bundleContext.getBundles(); -// long startBegin = System.currentTimeMillis(); -// for (int i = 0; i < bundles.length; i++) { -// Bundle bundle = bundles[i]; -// String symbolicName = bundle.getSymbolicName(); -// if (bundlesToStart.contains(symbolicName)) -// try { -// try { -// bundle.start(); -// if (OsgiBootUtils.isDebug()) -// debug("Bundle " + symbolicName + " started"); -// } catch (Exception e) { -// OsgiBootUtils.warn("Start of bundle " + symbolicName + " failed because of " + e -// + ", maybe bundle is not yet resolved," + " waiting and trying again."); -// waitForBundleResolvedOrActive(startBegin, bundle); -// bundle.start(); -// startedBundles.add(bundle); -// } -// notFoundBundles.remove(symbolicName); -// } catch (Exception e) { -// OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " + e.getMessage()); -// if (OsgiBootUtils.isDebug()) -// e.printStackTrace(); -// // was found even if start failed -// notFoundBundles.remove(symbolicName); -// } -// } -// -// for (int i = 0; i < notFoundBundles.size(); i++) -// OsgiBootUtils.warn("Bundle '" + notFoundBundles.get(i) + "' not started because it was not found."); -// -// // monitors that all bundles are started -// long beginMonitor = System.currentTimeMillis(); -// boolean allStarted = !(startedBundles.size() > 0); -// List notStarted = new ArrayList(); -// while (!allStarted && (System.currentTimeMillis() - beginMonitor) < defaultTimeout) { -// notStarted = new ArrayList(); -// allStarted = true; -// for (int i = 0; i < startedBundles.size(); i++) { -// Bundle bundle = (Bundle) startedBundles.get(i); -// // TODO check behaviour of lazs bundles -// if (bundle.getState() != Bundle.ACTIVE) { -// allStarted = false; -// notStarted.add(bundle.getSymbolicName()); -// } -// } -// try { -// Thread.sleep(100); -// } catch (InterruptedException e) { -// // silent -// } -// } -// long duration = System.currentTimeMillis() - beginMonitor; -// -// if (!allStarted) -// for (int i = 0; i < notStarted.size(); i++) -// OsgiBootUtils.warn("Bundle '" + notStarted.get(i) + "' not ACTIVE after " + (duration / 1000) + "s"); -// -// return allStarted; -// } - -// /** Waits for a bundle to become active or resolved */ -// @Deprecated -// private void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) throws Exception { -// int originalState = bundle.getState(); -// if ((originalState == Bundle.RESOLVED) || (originalState == Bundle.ACTIVE)) -// return; -// -// String originalStateStr = OsgiBootUtils.stateAsString(originalState); -// -// int currentState = bundle.getState(); -// while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) { -// long now = System.currentTimeMillis(); -// if ((now - startBegin) > defaultTimeout * 10) -// throw new Exception("Bundle " + bundle.getSymbolicName() + " was not RESOLVED or ACTIVE after " -// + (now - startBegin) + "ms (originalState=" + originalStateStr + ", currentState=" -// + OsgiBootUtils.stateAsString(currentState) + ")"); -// -// try { -// Thread.sleep(100l); -// } catch (InterruptedException e) { -// // silent -// } -// currentState = bundle.getState(); -// } -// } - /* * BUNDLE PATTERNS INSTALLATION */ @@ -556,6 +495,7 @@ public class OsgiBoot implements OsgiBootConstants { } /** Implements the path matching logic */ + @Deprecated public List getBundlesUrls(String baseUrl, String bundlePatterns) { List urls = new ArrayList(); if (bundlePatterns == null) @@ -650,16 +590,6 @@ public class OsgiBoot implements OsgiBootConstants { distributionBundle = new DistributionBundle(baseUrl, distributionUrl, localCache); } - // if (baseUrl != null && !(distributionUrl.startsWith("http") || - // distributionUrl.startsWith("file"))) { - // // relative url - // distributionBundle = new DistributionBundle(baseUrl, distributionUrl, - // localCache); - // } else { - // distributionBundle = new DistributionBundle(distributionUrl); - // if (baseUrl != null) - // distributionBundle.setBaseUrl(baseUrl); - // } distributionBundle.processUrl(); return distributionBundle.listUrls(); } @@ -725,10 +655,6 @@ public class OsgiBoot implements OsgiBootConstants { } } - protected void matchFile() { - - } - /* * LOW LEVEL UTILITIES */ @@ -771,6 +697,7 @@ public class OsgiBoot implements OsgiBootConstants { private void refreshFramework() { Bundle systemBundle = bundleContext.getBundle(0); FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class); + // TODO deal with refresh breaking native loading (e.g SWT) frameworkWiring.refreshBundles(null); } @@ -795,36 +722,8 @@ public class OsgiBoot implements OsgiBootConstants { * BEAN METHODS */ -// public boolean getDebug() { -// return OsgiBootUtils.debug; -// } - - // public void setDebug(boolean debug) { - // this.debug = debug; - // } - public BundleContext getBundleContext() { return bundleContext; } - public String getLocalCache() { - return localCache; - } - - // public void setDefaultTimeout(long defaultTimeout) { - // this.defaultTimeout = defaultTimeout; - // } - - // public boolean isExcludeSvn() { - // return excludeSvn; - // } - // - // public void setExcludeSvn(boolean excludeSvn) { - // this.excludeSvn = excludeSvn; - // } - - /* - * INTERNAL CLASSES - */ - }