From: Mathieu Baudier Date: Tue, 5 Mar 2024 15:19:05 +0000 (+0100) Subject: Clean up Argeo Init X-Git-Tag: v2.3.28~27 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=6bfcb81dd21d8fdd9094610c00f5f8ad9c6a36a7 Clean up Argeo Init --- diff --git a/org.argeo.init/src/org/argeo/api/a2/A2Branch.java b/org.argeo.init/src/org/argeo/api/a2/A2Branch.java index 1db82a74a..0b4ef36f7 100644 --- a/org.argeo.init/src/org/argeo/api/a2/A2Branch.java +++ b/org.argeo.init/src/org/argeo/api/a2/A2Branch.java @@ -1,10 +1,11 @@ package org.argeo.api.a2; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.util.Collections; import java.util.SortedMap; import java.util.TreeMap; -import org.argeo.init.osgi.OsgiBootUtils; import org.osgi.framework.Version; /** @@ -13,6 +14,8 @@ import org.osgi.framework.Version; * compatibility. */ public class A2Branch implements Comparable { + private final static Logger logger = System.getLogger(A2Branch.class.getName()); + private final A2Component component; private final String id; @@ -31,8 +34,9 @@ public class A2Branch implements Comparable { A2Module getOrAddModule(Version version, Object locator) { if (modules.containsKey(version)) { A2Module res = modules.get(version); - if (OsgiBootUtils.isDebug() && !res.getLocator().equals(locator)) { - OsgiBootUtils.debug("Inconsistent locator " + locator + " (registered: " + res.getLocator() + ")"); + if (!res.getLocator().equals(locator)) { + logger.log(Level.TRACE, + () -> "Inconsistent locator " + locator + " (registered: " + res.getLocator() + ")"); } return res; } else diff --git a/org.argeo.init/src/org/argeo/api/a2/A2Contribution.java b/org.argeo.init/src/org/argeo/api/a2/A2Contribution.java index f099ceb2b..a5ec896e9 100644 --- a/org.argeo.init/src/org/argeo/api/a2/A2Contribution.java +++ b/org.argeo.init/src/org/argeo/api/a2/A2Contribution.java @@ -92,6 +92,7 @@ public class A2Contribution implements Comparable { return Os.local().toString() + "/" + Arch.local().toString(); } + /** Well-known operating systems. */ static enum Os { LINUX, WIN32, MACOSX, UNKOWN; @@ -100,6 +101,7 @@ public class A2Contribution implements Comparable { return name().toLowerCase(); } + /** The local operating system. */ public static Os local() { String osStr = System.getProperty("os.name").toLowerCase(); if (osStr.startsWith("linux")) @@ -113,6 +115,7 @@ public class A2Contribution implements Comparable { } + /** Well-known processor architectures. */ static enum Arch { X86_64, AARCH64, X86, POWERPC, UNKOWN; @@ -121,6 +124,7 @@ public class A2Contribution implements Comparable { return name().toLowerCase(); } + /** The locla processor architecture. */ public static Arch local() { String archStr = System.getProperty("os.arch").toLowerCase(); return switch (archStr) { diff --git a/org.argeo.init/src/org/argeo/api/a2/ClasspathSource.java b/org.argeo.init/src/org/argeo/api/a2/ClasspathSource.java index 2f1cf95fa..b702d35a0 100644 --- a/org.argeo.init/src/org/argeo/api/a2/ClasspathSource.java +++ b/org.argeo.init/src/org/argeo/api/a2/ClasspathSource.java @@ -2,12 +2,13 @@ package org.argeo.api.a2; import java.io.File; import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; -import org.argeo.init.osgi.OsgiBootUtils; import org.osgi.framework.Version; /** @@ -15,13 +16,14 @@ import org.osgi.framework.Version; * been started. */ public class ClasspathSource extends AbstractProvisioningSource { - + private final static Logger logger = System.getLogger(ClasspathSource.class.getName()); + public ClasspathSource() { super(true); } void load() throws IOException { - A2Contribution classpathContribution = getOrAddContribution( A2Contribution.CLASSPATH); + A2Contribution classpathContribution = getOrAddContribution(A2Contribution.CLASSPATH); List classpath = Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)); parts: for (String part : classpath) { Path file = Paths.get(part); @@ -35,8 +37,7 @@ public class ClasspathSource extends AbstractProvisioningSource { String moduleName = readSymbolicNameFromModule(file); A2Component component = classpathContribution.getOrAddComponent(moduleName); A2Module module = component.getOrAddModule(version, file); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Registered " + module); + logger.log(Level.TRACE, () -> "Registered " + module); } } diff --git a/org.argeo.init/src/org/argeo/api/a2/FsA2Source.java b/org.argeo.init/src/org/argeo/api/a2/FsA2Source.java index ebb602049..e63a6f175 100644 --- a/org.argeo.init/src/org/argeo/api/a2/FsA2Source.java +++ b/org.argeo.init/src/org/argeo/api/a2/FsA2Source.java @@ -1,6 +1,8 @@ package org.argeo.api.a2; import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.DirectoryStream; @@ -13,11 +15,12 @@ import java.util.SortedMap; import java.util.StringJoiner; import java.util.TreeMap; -import org.argeo.init.osgi.OsgiBootUtils; import org.osgi.framework.Version; /** A file system {@link AbstractProvisioningSource} in A2 format. */ public class FsA2Source extends AbstractProvisioningSource implements A2Source { + private final static Logger logger = System.getLogger(FsA2Source.class.getName()); + private final Path base; private final Map variantsXOr; @@ -112,14 +115,13 @@ public class FsA2Source extends AbstractProvisioningSource implements A2Source { if (versionStr != null) { version = new Version(versionStr); } else { - OsgiBootUtils.debug("Ignore " + modulePath + " since version cannot be found"); + logger.log(Level.TRACE, () -> "Ignore " + modulePath + " since version cannot be found"); continue modules; } // } A2Component component = contribution.getOrAddComponent(componentName); A2Module module = component.getOrAddModule(version, modulePath); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Registered " + module); + logger.log(Level.TRACE, () -> "Registered " + module); } } } diff --git a/org.argeo.init/src/org/argeo/api/a2/FsM2Source.java b/org.argeo.init/src/org/argeo/api/a2/FsM2Source.java index f63a90468..7cf2a042c 100644 --- a/org.argeo.init/src/org/argeo/api/a2/FsM2Source.java +++ b/org.argeo.init/src/org/argeo/api/a2/FsM2Source.java @@ -2,6 +2,8 @@ package org.argeo.api.a2; import java.io.File; import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; @@ -9,11 +11,12 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import org.argeo.init.osgi.OsgiBootUtils; import org.osgi.framework.Version; /** A file system {@link AbstractProvisioningSource} in Maven 2 format. */ public class FsM2Source extends AbstractProvisioningSource { + private final static Logger logger = System.getLogger(FsM2Source.class.getName()); + private final Path base; public FsM2Source(Path base) { @@ -45,8 +48,7 @@ public class FsM2Source extends AbstractProvisioningSource { A2Contribution contribution = getOrAddContribution(contributionName); A2Component component = contribution.getOrAddComponent(moduleName); A2Module module = component.getOrAddModule(version, file); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Registered " + module); + logger.log(Level.TRACE, () -> "Registered " + module); } return super.visitFile(file, attrs); } diff --git a/org.argeo.init/src/org/argeo/api/a2/OsgiContext.java b/org.argeo.init/src/org/argeo/api/a2/OsgiContext.java index dfed170d1..4ec186bf9 100644 --- a/org.argeo.init/src/org/argeo/api/a2/OsgiContext.java +++ b/org.argeo.init/src/org/argeo/api/a2/OsgiContext.java @@ -1,6 +1,8 @@ package org.argeo.api.a2; -import org.argeo.init.osgi.OsgiBootUtils; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; + import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -10,6 +12,8 @@ import org.osgi.framework.Version; * A running OSGi bundle context seen as a {@link AbstractProvisioningSource}. */ class OsgiContext extends AbstractProvisioningSource { + private final static Logger logger = System.getLogger(OsgiContext.class.getName()); + private final BundleContext bc; private A2Contribution runtimeContribution; @@ -41,8 +45,8 @@ class OsgiContext extends AbstractProvisioningSource { Version version = bundle.getVersion(); A2Component component = runtimeContribution.getOrAddComponent(componentId); A2Module module = component.getOrAddModule(version, bundle); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Registered bundle module " + module + " (location id: " + bundle.getLocation() + ")"); + logger.log(Level.TRACE, + () -> "Registered bundle module " + module + " (location id: " + bundle.getLocation() + ")"); } } diff --git a/org.argeo.init/src/org/argeo/api/a2/ProvisioningManager.java b/org.argeo.init/src/org/argeo/api/a2/ProvisioningManager.java index 104f08a5d..7a17932df 100644 --- a/org.argeo.init/src/org/argeo/api/a2/ProvisioningManager.java +++ b/org.argeo.init/src/org/argeo/api/a2/ProvisioningManager.java @@ -1,10 +1,15 @@ package org.argeo.api.a2; +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.ERROR; +import static java.lang.System.Logger.Level.INFO; +import static java.lang.System.Logger.Level.TRACE; import static org.argeo.api.a2.A2Source.SCHEME_A2; import static org.argeo.api.a2.A2Source.SCHEME_A2_REFERENCE; import java.io.File; import java.io.UnsupportedEncodingException; +import java.lang.System.Logger; import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -22,7 +27,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.argeo.init.osgi.OsgiBootUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -31,9 +35,11 @@ import org.osgi.framework.wiring.FrameworkWiring; /** Loads provisioning sources into an OSGi context. */ public class ProvisioningManager { - BundleContext bc; - OsgiContext osgiContext; - List sources = Collections.synchronizedList(new ArrayList<>()); + private final static Logger logger = System.getLogger(ProvisioningManager.class.getName()); + + private BundleContext bc; + private OsgiContext osgiContext; + private List sources = Collections.synchronizedList(new ArrayList<>()); public ProvisioningManager(BundleContext bc) { this.bc = bc; @@ -93,7 +99,7 @@ public class ProvisioningManager { includes, excludes); source.load(); addSource(source); - OsgiBootUtils.info("Registered " + uri + " as source"); + logger.log(INFO, () -> "Registered " + uri + " as source"); // OS specific / native String localRelPath = A2Contribution.localOsArchRelativePath(); @@ -103,10 +109,11 @@ public class ProvisioningManager { SCHEME_A2_REFERENCE.equals(u.getScheme()), includes, excludes); libSource.load(); addSource(libSource); - OsgiBootUtils.info("Registered OS-specific " + uri + " as source (" + localRelPath + ")"); + logger.log(DEBUG, + () -> "Registered OS-specific base " + localLibBase + " for source " + uri); } } else { - OsgiBootUtils.debug("Source " + base + " does not exist, ignoring."); + logger.log(TRACE, () -> "Source " + base + " does not exist, ignoring."); } } else { throw new UnsupportedOperationException( @@ -133,12 +140,12 @@ public class ProvisioningManager { baseStr = '/' + baseStr.replace(File.separatorChar, '/'); URI baseUri = new URI(A2Source.SCHEME_A2, null, null, 0, baseStr, null, null); registerSource(baseUri.toString()); - OsgiBootUtils.debug("Default source from framework location " + frameworkLocation); + logger.log(TRACE, () -> "Default source from framework location " + frameworkLocation); return true; } } } catch (Exception e) { - OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e); + logger.log(ERROR, "Cannot register default source based on framework location " + frameworkLocation, e); } return false; } @@ -176,20 +183,19 @@ public class ProvisioningManager { // TODO remove old module? Or keep update history? osgiContext.registerBundle(bundle); if (compare == 0) - OsgiBootUtils - .debug("Updated bundle " + bundle.getLocation() + " to same version " + moduleVersion); + logger.log(TRACE, + () -> "Updated bundle " + bundle.getLocation() + " to same version " + moduleVersion); else - OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); + logger.log(INFO, "Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); return bundle; } else { - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Did not install as bundle module " + module - + " since a module with higher version " + lastOsgiModule.getVersion() - + " is already installed for branch " + osgiBranch); + logger.log(TRACE, + () -> "Did not install as bundle module " + module + " since a module with higher version " + + lastOsgiModule.getVersion() + " is already installed for branch " + osgiBranch); } } } catch (Exception e) { - OsgiBootUtils.error("Could not install module " + module + ": " + e.getMessage(), e); + logger.log(ERROR, "Could not install module " + module + ": " + e.getMessage(), e); } return null; } @@ -214,10 +220,10 @@ public class ProvisioningManager { String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST); if (fragmentHost != null) fragmentsUpdated = true; - OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); + logger.log(INFO, "Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); updatedBundles.add(bundle); } catch (Exception e) { - OsgiBootUtils.error("Cannot update with module " + module, e); + logger.log(ERROR, "Cannot update with module " + module, e); } } } diff --git a/org.argeo.init/src/org/argeo/api/init/RuntimeManager.java b/org.argeo.init/src/org/argeo/api/init/RuntimeManager.java index 1f4a3eca4..113aa46c4 100644 --- a/org.argeo.init/src/org/argeo/api/init/RuntimeManager.java +++ b/org.argeo.init/src/org/argeo/api/init/RuntimeManager.java @@ -7,5 +7,5 @@ import java.util.function.Consumer; public interface RuntimeManager { public void startRuntime(String relPath, Consumer> configCallback); - public void stopRuntime(String relPath, boolean async); + public void closeRuntime(String relPath, boolean async); } diff --git a/org.argeo.init/src/org/argeo/init/RuntimeManagerMain.java b/org.argeo.init/src/org/argeo/init/RuntimeManagerMain.java index 72b673b68..9c8692c4b 100644 --- a/org.argeo.init/src/org/argeo/init/RuntimeManagerMain.java +++ b/org.argeo.init/src/org/argeo/init/RuntimeManagerMain.java @@ -27,6 +27,8 @@ import org.argeo.internal.init.InternalState; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.launch.Framework; /** * Dynamically configures and launches multiple runtimes, coordinated by a main @@ -91,7 +93,7 @@ public class RuntimeManagerMain implements RuntimeManager { Map shutdowning = new HashMap<>(runtimeContexts); for (String id : new HashSet<>(runtimeContexts.keySet())) { logger.log(Logger.Level.DEBUG, "Shutting down runtime " + id + " ..."); - stopRuntime(id, true); + closeRuntime(id, true); } for (String id : shutdowning.keySet()) try { @@ -99,8 +101,9 @@ public class RuntimeManagerMain implements RuntimeManager { runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT); } catch (InterruptedException e) { // silent + } catch (Exception e) { + logger.log(Logger.Level.DEBUG, "Cannot wait for " + id + " to shutdown", e); } - // shutdown manager runtime try { InternalState.getMainRuntimeContext().close(); @@ -115,7 +118,7 @@ public class RuntimeManagerMain implements RuntimeManager { public static void loadConfig(Path dir, Map config) { try { - System.out.println("Load from " + dir); +// System.out.println("Load from " + dir); Path jvmArgsPath = dir.resolve(JVM_ARGS); if (!Files.exists(jvmArgsPath)) { // load from parent directory @@ -138,7 +141,7 @@ public class RuntimeManagerMain implements RuntimeManager { } OsgiRuntimeContext loadRuntime(String relPath, Consumer> configCallback) { - stopRuntime(relPath, false); + closeRuntime(relPath, false); Path stateArea = baseStateArea.resolve(relPath); Path configArea = baseConfigArea.resolve(relPath); Map config = new HashMap<>(); @@ -160,9 +163,20 @@ public class RuntimeManagerMain implements RuntimeManager { public void startRuntime(String relPath, Consumer> configCallback) { OsgiRuntimeContext runtimeContext = loadRuntime(relPath, configCallback); runtimeContext.run(); + Framework framework = runtimeContext.getFramework(); + if (framework != null) {// in case the framework has closed very quickly after run + framework.getBundleContext().addFrameworkListener((e) -> { + if (e.getType() >= FrameworkEvent.STOPPED) { + logger.log(Level.DEBUG, "Externally stopped runtime " + relPath + ". Unregistering...", e); + runtimeContexts.remove(relPath); + } + }); + } else { + closeRuntime(relPath, false); + } } - public void stopRuntime(String relPath, boolean async) { + public void closeRuntime(String relPath, boolean async) { if (!runtimeContexts.containsKey(relPath)) return; RuntimeContext runtimeContext = runtimeContexts.get(relPath); @@ -182,7 +196,7 @@ public class RuntimeManagerMain implements RuntimeManager { public static void main(String[] args) { ThinLoggerFinder.reloadConfiguration(); - logger.log(Logger.Level.INFO, () -> "Argeo Init starting with PID " + ProcessHandle.current().pid()); + logger.log(Logger.Level.DEBUG, () -> "Argeo Init starting with PID " + ProcessHandle.current().pid()); Map env = System.getenv(); // for (String envName : new TreeSet<>(env.keySet())) { // System.out.format("%s=%s%n", envName, env.get(envName)); diff --git a/org.argeo.init/src/org/argeo/init/logging/ThinLogging.java b/org.argeo.init/src/org/argeo/init/logging/ThinLogging.java index 30a149bc9..2b2f6b3a7 100644 --- a/org.argeo.init/src/org/argeo/init/logging/ThinLogging.java +++ b/org.argeo.init/src/org/argeo/init/logging/ThinLogging.java @@ -393,11 +393,11 @@ class ThinLogging implements Consumer> { case "org.osgi.service.log.Logger": case "org.eclipse.osgi.internal.log.LoggerImpl": case "org.argeo.api.cms.CmsLog": - case "org.argeo.init.osgi.OsgiBootUtils": - case "org.slf4j.impl.ArgeoLogger": - case "org.argeo.cms.internal.osgi.CmsOsgiLogger": case "org.eclipse.jetty.util.log.Slf4jLog": case "sun.util.logging.internal.LoggingProviderImpl$JULWrapper": + case "org.slf4j.impl.ArgeoLogger": + case "org.argeo.cms.internal.osgi.CmsOsgiLogger": + case "org.argeo.init.osgi.OsgiBootUtils": lowestLoggerInterface = i; continue stack; default: diff --git a/org.argeo.init/src/org/argeo/init/osgi/AdminThread.java b/org.argeo.init/src/org/argeo/init/osgi/AdminThread.java deleted file mode 100644 index e493e2c7e..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/AdminThread.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.argeo.init.osgi; - -import java.io.File; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.launch.Framework; - -/** Monitors the runtime and can shut it down. */ -@Deprecated -public class AdminThread extends Thread { - public final static String PROP_ARGEO_OSGI_SHUTDOWN_FILE = "argeo.osgi.shutdownFile"; - private File shutdownFile; - private final BundleContext bundleContext; - - public AdminThread(BundleContext bundleContext) { - super("OSGi Boot Admin"); - this.bundleContext = bundleContext; - if (System.getProperty(PROP_ARGEO_OSGI_SHUTDOWN_FILE) != null) { - shutdownFile = new File( - System.getProperty(PROP_ARGEO_OSGI_SHUTDOWN_FILE)); - if (!shutdownFile.exists()) { - shutdownFile = null; - OsgiBootUtils.warn("Shutdown file " + shutdownFile - + " not found, feature deactivated"); - } - } - } - - public void run() { - if (shutdownFile != null) { - // wait for file to be removed - while (shutdownFile.exists()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - Framework framework = (Framework) bundleContext.getBundle(0); - try { - // shutdown framework - framework.stop(); - // wait 10 mins for shutdown - framework.waitForStop(10 * 60 * 1000); - // close VM - System.exit(0); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - } -} diff --git a/org.argeo.init/src/org/argeo/init/osgi/BundlesSet.java b/org.argeo.init/src/org/argeo/init/osgi/BundlesSet.java index 863ee0084..6a13e6749 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/BundlesSet.java +++ b/org.argeo.init/src/org/argeo/init/osgi/BundlesSet.java @@ -1,13 +1,18 @@ package org.argeo.init.osgi; +import static java.lang.System.Logger.Level.TRACE; + import java.io.File; import java.io.IOException; +import java.lang.System.Logger; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; /** Intermediary structure used by path matching */ class BundlesSet { + private final static Logger logger = System.getLogger(BundlesSet.class.getName()); + private String baseUrl = "reference:file";// not used yet private final String dir; private List includes = new ArrayList(); @@ -25,8 +30,7 @@ class BundlesSet { dirPath = dirPath.substring("file:".length()); dir = new File(dirPath.replace('/', File.separatorChar)).getCanonicalPath(); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Base dir: " + dir); + logger.log(TRACE, () -> "Base dir: " + dir); } catch (IOException e) { throw new RuntimeException("Cannot convert to absolute path", e); } diff --git a/org.argeo.init/src/org/argeo/init/osgi/DistributionBundle.java b/org.argeo.init/src/org/argeo/init/osgi/DistributionBundle.java index 35b66e6b7..937c3881b 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/DistributionBundle.java +++ b/org.argeo.init/src/org/argeo/init/osgi/DistributionBundle.java @@ -1,9 +1,12 @@ package org.argeo.init.osgi; +import static java.lang.System.Logger.Level.WARNING; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.System.Logger; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -32,6 +35,8 @@ import org.osgi.framework.Version; * name of the URL and of the content of the index. */ public class DistributionBundle { + private final static Logger logger = System.getLogger(DistributionBundle.class.getName()); + private final static String INDEX_FILE_NAME = "modularDistribution.csv"; private final String url; @@ -113,7 +118,7 @@ public class DistributionBundle { public void processUrl() { JarInputStream jarIn = null; try { - URL u = new URL(url); + URL u = new URI(url).toURL(); // local cache URI localUri = new URI(localCache + relativeUrl); @@ -213,7 +218,7 @@ public class DistributionBundle { try { localUri = new URI(localCache + relativeUrl); } catch (URISyntaxException e) { - OsgiBootUtils.warn(e.getMessage()); + logger.log(WARNING, e.getMessage()); localUri = null; } Version version = new Version(osgiArtifact.getVersion()); diff --git a/org.argeo.init/src/org/argeo/init/osgi/Launcher.java b/org.argeo.init/src/org/argeo/init/osgi/Launcher.java deleted file mode 100644 index 778c08a70..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/Launcher.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.argeo.init.osgi; - -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import org.osgi.framework.BundleContext; - -/** An OSGi launcher executing first another class in the system class path. */ -public class Launcher { - - public static void main(String[] args) { - // Try to load system properties - String systemPropertiesFilePath = getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE); - if (systemPropertiesFilePath != null) { - FileInputStream in; - try { - in = new FileInputStream(systemPropertiesFilePath); - System.getProperties().load(in); - } catch (IOException e1) { - throw new RuntimeException("Cannot load system properties from " + systemPropertiesFilePath, e1); - } - if (in != null) { - try { - in.close(); - } catch (Exception e) { - // silent - } - } - } - - // Start main class - startMainClass(); - - // Start Equinox - BundleContext bundleContext = null; - try { - bundleContext = OsgiBootUtils.launch(OsgiBootUtils.equinoxArgsToConfiguration(args)).getBundleContext(); - } catch (Exception e) { - throw new RuntimeException("Cannot start Equinox.", e); - } - - // OSGi bootstrap - OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - osgiBoot.bootstrap(); - } - - protected static void startMainClass() { - String className = getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPCLASS); - if (className == null) - return; - - String line = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPARGS, ""); - - String[] uiArgs = readArgumentsFromLine(line); - - try { - // Launch main method using reflection - Class clss = Class.forName(className); - Class[] mainArgsClasses = new Class[] { uiArgs.getClass() }; - Object[] mainArgs = { uiArgs }; - Method mainMethod = clss.getMethod("main", mainArgsClasses); - mainMethod.invoke(null, mainArgs); - } catch (Exception e) { - throw new RuntimeException("Cannot start main class.", e); - } - - } - - /** - * Transform a line into an array of arguments, taking "" as single arguments. - * (nested \" are not supported) - */ - private static String[] readArgumentsFromLine(String lineOrig) { - String line = lineOrig.trim();// remove trailing spaces - List args = new ArrayList(); - StringBuffer curr = new StringBuffer(""); - boolean inQuote = false; - char[] arr = line.toCharArray(); - for (int i = 0; i < arr.length; i++) { - char c = arr[i]; - switch (c) { - case '\"': - inQuote = !inQuote; - break; - case ' ': - if (!inQuote) {// otherwise, no break: goes to default - if (curr.length() > 0) { - args.add(curr.toString()); - curr = new StringBuffer(""); - } - break; - } - default: - curr.append(c); - break; - } - } - - // Add last arg - if (curr.length() > 0) { - args.add(curr.toString()); - curr = null; - } - - String[] res = new String[args.size()]; - for (int i = 0; i < args.size(); i++) { - res[i] = args.get(i).toString(); - } - return res; - } - - public static String getProperty(String name, String defaultValue) { - final String value; - if (defaultValue != null) - value = System.getProperty(name, defaultValue); - else - value = System.getProperty(name); - - if (value == null || value.equals("")) - return null; - else - return value; - } - - public static String getProperty(String name) { - return getProperty(name, null); - } - -} diff --git a/org.argeo.init/src/org/argeo/init/osgi/Main.java b/org.argeo.init/src/org/argeo/init/osgi/Main.java deleted file mode 100644 index ce83329b6..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/Main.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.argeo.init.osgi; - -import java.lang.management.ManagementFactory; - -public class Main { - - public static void main(String[] args) { - String mainClass = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPCLASS); - if (mainClass == null) { - throw new IllegalArgumentException( - "System property " + OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPCLASS + " must be specified"); - } - - OsgiBuilder osgi = new OsgiBuilder(); - String distributionUrl = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_DISTRIBUTION_URL); - if (distributionUrl != null) - osgi.install(distributionUrl); - // osgi.conf("argeo.node.useradmin.uris", "os:///"); - // osgi.conf("osgi.clean", "true"); - // osgi.conf("osgi.console", "true"); - osgi.launch(); - - if (OsgiBootUtils.isDebug()) { - long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime(); - String jvmUptimeStr = (jvmUptime / 1000) + "." + (jvmUptime % 1000) + "s"; - OsgiBootUtils.debug("Ready to launch " + mainClass + " in " + jvmUptimeStr); - } - - osgi.main(mainClass, args); - - osgi.shutdown(); - - } - -} diff --git a/org.argeo.init/src/org/argeo/init/osgi/NodeRunner.java b/org.argeo.init/src/org/argeo/init/osgi/NodeRunner.java deleted file mode 100644 index 336965060..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/NodeRunner.java +++ /dev/null @@ -1,235 +0,0 @@ -package org.argeo.init.osgi; - -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.ServiceLoader; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.launch.Framework; -import org.osgi.framework.launch.FrameworkFactory; - -/** Launch an OSGi framework and deploy a CMS Node into it. */ -public class NodeRunner { - private Long timeout = 30 * 1000l; - private final Path baseDir; - private final Path confDir; - private final Path dataDir; - - private String baseUrl = "http://forge.argeo.org/data/java/argeo-2.1/"; - private String distributionUrl = null; - - private Framework framework = null; - - public NodeRunner(String distributionUrl, Path baseDir) { - this.distributionUrl = distributionUrl; - Path mavenBase = Paths.get(System.getProperty("user.home") + "/.m2/repository"); - Path osgiBase = Paths.get("/user/share/osgi"); - if (Files.exists(mavenBase)) { - Path mavenPath = mavenBase.resolve(distributionUrl); - if (Files.exists(mavenPath)) - baseUrl = mavenBase.toUri().toString(); - } else if (Files.exists(osgiBase)) { - Path osgiPath = osgiBase.resolve(distributionUrl); - if (Files.exists(osgiPath)) - baseUrl = osgiBase.toUri().toString(); - } - - this.baseDir = baseDir; - this.confDir = this.baseDir.resolve("state"); - this.dataDir = this.baseDir.resolve("data"); - - } - - public void start() { - long begin = System.currentTimeMillis(); - // log4j - Path log4jFile = confDir.resolve("log4j.properties"); - if (!Files.exists(log4jFile)) - copyResource("/org/argeo/osgi/boot/log4j.properties", log4jFile); - System.setProperty("log4j.configuration", "file://" + log4jFile.toAbsolutePath()); - - // Start Equinox - try { - ServiceLoader ff = ServiceLoader.load(FrameworkFactory.class); - FrameworkFactory frameworkFactory = ff.iterator().next(); - Map configuration = new HashMap(); - configuration.put("osgi.configuration.area", confDir.toAbsolutePath().toString()); - configuration.put("osgi.instance.area", dataDir.toAbsolutePath().toString()); - defaultConfiguration(configuration); - - framework = frameworkFactory.newFramework(configuration); - framework.start(); - info("## Date : " + new Date()); - info("## Data : " + dataDir.toAbsolutePath()); - } catch (Exception e) { - throw new IllegalStateException("Cannot start OSGi framework", e); - } - BundleContext bundleContext = framework.getBundleContext(); - try { - - // Spring configs currently require System properties - // System.getProperties().putAll(configuration); - - // expected by JAAS as System.property FIXME - System.setProperty("osgi.instance.area", bundleContext.getProperty("osgi.instance.area")); - - // OSGi bootstrap - OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - - osgiBoot.installUrls(osgiBoot.getDistributionUrls(distributionUrl, baseUrl)); - - // Start runtime - Properties startProperties = new Properties(); - // TODO make it possible to override it - startProperties.put("argeo.osgi.start.2.node", - "org.eclipse.equinox.http.servlet,org.eclipse.equinox.http.jetty," - + "org.eclipse.equinox.metatype,org.eclipse.equinox.cm,org.eclipse.rap.rwt.osgi"); - startProperties.put("argeo.osgi.start.3.node", "org.argeo.cms"); - startProperties.put("argeo.osgi.start.4.node", - "org.eclipse.gemini.blueprint.extender,org.eclipse.equinox.http.registry"); - osgiBoot.startBundles(startProperties); - - // Find node repository - ServiceReference sr = null; - while (sr == null) { - sr = bundleContext.getServiceReference("javax.jcr.Repository"); - if (System.currentTimeMillis() - begin > timeout) - throw new RuntimeException("Could find node after " + timeout + "ms"); - Thread.sleep(100); - } - Object nodeDeployment = bundleContext.getService(sr); - info("Node Deployment " + nodeDeployment); - - // Initialization completed - long duration = System.currentTimeMillis() - begin; - info("## CMS Launcher initialized in " + (duration / 1000) + "s " + (duration % 1000) + "ms"); - } catch (Exception e) { - shutdown(); - throw new RuntimeException("Cannot start CMS", e); - } finally { - - } - } - - private void defaultConfiguration(Map configuration) { - // all permissions to OSGi security manager - Path policyFile = confDir.resolve("node.policy"); - if (!Files.exists(policyFile)) - copyResource("/org/argeo/osgi/boot/node.policy", policyFile); - configuration.put("java.security.policy", "file://" + policyFile.toAbsolutePath()); - - configuration.put("org.eclipse.rap.workbenchAutostart", "false"); - configuration.put("org.eclipse.equinox.http.jetty.autostart", "false"); - configuration.put("org.osgi.framework.bootdelegation", - "com.sun.jndi.ldap,com.sun.jndi.ldap.sasl,com.sun.security.jgss,com.sun.jndi.dns," - + "com.sun.nio.file,com.sun.nio.sctp"); - - // Do clean - // configuration.put("osgi.clean", "true"); - // if (args.length == 0) { - // configuration.put("osgi.console", ""); - // } - } - - public void shutdown() { - try { - framework.stop(); - framework.waitForStop(15 * 1000); - } catch (Exception silent) { - } - } - - public Path getConfDir() { - return confDir; - } - - public Path getDataDir() { - return dataDir; - } - - public Framework getFramework() { - return framework; - } - - public static void main(String[] args) { - try { - String distributionUrl; - Path executionDir; - if (args.length == 2) { - distributionUrl = args[0]; - executionDir = Paths.get(args[1]); - } else if (args.length == 1) { - executionDir = Paths.get(System.getProperty("user.dir")); - distributionUrl = args[0]; - } else if (args.length == 0) { - executionDir = Paths.get(System.getProperty("user.dir")); - distributionUrl = "org/argeo/commons/org.argeo.dep.cms.sdk/2.1.70/org.argeo.dep.cms.sdk-2.1.70.jar"; - }else{ - printUsage(); - System.exit(1); - return; - } - - NodeRunner nodeRunner = new NodeRunner(distributionUrl, executionDir); - nodeRunner.start(); -// if (args.length != 0) -// System.exit(0); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - - protected static void info(Object msg) { - System.out.println(msg); - } - - protected static void err(Object msg) { - System.err.println(msg); - } - - protected static void debug(Object msg) { - System.out.println(msg); - } - - protected static void copyResource(String resource, Path targetFile) { - InputStream input = null; - OutputStream output = null; - try { - input = NodeRunner.class.getResourceAsStream(resource); - Files.createDirectories(targetFile.getParent()); - output = Files.newOutputStream(targetFile); - byte[] buf = new byte[8192]; - while (true) { - int length = input.read(buf); - if (length < 0) - break; - output.write(buf, 0, length); - } - } catch (Exception e) { - throw new RuntimeException("Cannot write " + resource + " file to " + targetFile, e); - } finally { - try { - input.close(); - } catch (Exception ignore) { - } - try { - output.close(); - } catch (Exception ignore) { - } - } - - } - - static void printUsage(){ - err("Usage: "); - } -} 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 67ee7b6df..0d475ad21 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java +++ b/org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java @@ -1,9 +1,13 @@ package org.argeo.init.osgi; -import static org.argeo.init.osgi.OsgiBootUtils.debug; -import static org.argeo.init.osgi.OsgiBootUtils.warn; +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.ERROR; +import static java.lang.System.Logger.Level.TRACE; +import static java.lang.System.Logger.Level.WARNING; import java.io.File; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -14,7 +18,9 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import java.util.ServiceLoader; import java.util.Set; import java.util.SortedMap; import java.util.StringTokenizer; @@ -28,6 +34,8 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.Version; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; import org.osgi.framework.startlevel.BundleStartLevel; import org.osgi.framework.startlevel.FrameworkStartLevel; import org.osgi.framework.wiring.FrameworkWiring; @@ -37,7 +45,9 @@ import org.osgi.framework.wiring.FrameworkWiring; * properties. The approach is to generate list of URLs based on various * methods, configured via properties. */ -public class OsgiBoot implements OsgiBootConstants { +public class OsgiBoot { + private final static Logger logger = System.getLogger(OsgiBoot.class.getName()); + @Deprecated final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles"; final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl"; @@ -129,7 +139,7 @@ public class OsgiBoot implements OsgiBootConstants { String osgiInstancePath = getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA); String osgiConfigurationPath = getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA); String osgiSharedConfigurationPath = getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA); - OsgiBootUtils.info("OSGi bootstrap starting" // + logger.log(DEBUG, () -> "OSGi bootstrap starting" // + (osgiInstancePath != null ? " data: " + osgiInstancePath + "" : "") // + (osgiConfigurationPath != null ? " state: " + osgiConfigurationPath + "" : "") // + (osgiSharedConfigurationPath != null ? " config: " + osgiSharedConfigurationPath + "" : "") // @@ -153,28 +163,28 @@ public class OsgiBoot implements OsgiBootConstants { // complete long duration = System.currentTimeMillis() - begin; - OsgiBootUtils.info("OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s (" + logger.log(DEBUG, () -> "OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s (" + duration + "ms), " + bundleContext.getBundles().length + " bundles"); } catch (RuntimeException e) { - OsgiBootUtils.error("OSGi bootstrap FAILED", e); + logger.log(ERROR, "OSGi bootstrap FAILED", e); throw e; } // diagnostics - if (OsgiBootUtils.isDebug()) { + if (logger.isLoggable(TRACE)) { OsgiBootDiagnostics diagnostics = new OsgiBootDiagnostics(bundleContext); diagnostics.checkUnresolved(); Map> duplicatePackages = diagnostics.findPackagesExportedTwice(); if (duplicatePackages.size() > 0) { - OsgiBootUtils.info("Packages exported twice:"); + logger.log(TRACE, "Packages exported twice:"); Iterator it = duplicatePackages.keySet().iterator(); while (it.hasNext()) { String pkgName = it.next(); - OsgiBootUtils.info(pkgName); + logger.log(TRACE, pkgName); Set bdles = duplicatePackages.get(pkgName); Iterator bdlesIt = bdles.iterator(); while (bdlesIt.hasNext()) - OsgiBootUtils.info(" " + bdlesIt.next()); + logger.log(TRACE, " " + bdlesIt.next()); } } } @@ -221,21 +231,20 @@ public class OsgiBoot implements OsgiBootConstants { try { if (installedBundles.containsKey(url)) { Bundle bundle = (Bundle) installedBundles.get(url); - if (OsgiBootUtils.isDebug()) - debug("Bundle " + bundle.getSymbolicName() + " already installed from " + url); + logger.log(TRACE, () -> "Bundle " + bundle.getSymbolicName() + " already installed from " + url); } else if (url.contains("/" + InitConstants.SYMBOLIC_NAME_EQUINOX + "/") || url.contains("/" + InitConstants.SYMBOLIC_NAME_INIT + "/")) { - if (OsgiBootUtils.isDebug()) - warn("Skip " + url); + if (logger.isLoggable(TRACE)) + logger.log(WARNING, "Skip " + url); return; } else { Bundle bundle = bundleContext.installBundle(url); if (url.startsWith("http")) - OsgiBootUtils - .info("Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); - else if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug( - "Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); + logger.log(DEBUG, + () -> "Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); + else + logger.log(TRACE, + () -> "Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); assert bundle.getSymbolicName() != null; // uninstall previous versions bundles: for (Bundle b : bundleContext.getBundles()) { @@ -250,17 +259,17 @@ public class OsgiBoot implements OsgiBootConstants { if (bundleV.getMicro() > bV.getMicro()) { // uninstall older bundles b.uninstall(); - OsgiBootUtils.debug("Uninstalled " + b); + logger.log(TRACE, () -> "Uninstalled " + b); } else if (bundleV.getMicro() < bV.getMicro()) { // uninstall just installed bundle if newer bundle.uninstall(); - OsgiBootUtils.debug("Uninstalled " + bundle); + logger.log(TRACE, () -> "Uninstalled " + bundle); break bundles; } else { // uninstall any other with same major/minor if (!bundleV.getQualifier().equals(bV.getQualifier())) { b.uninstall(); - OsgiBootUtils.debug("Uninstalled " + b); + logger.log(TRACE, () -> "Uninstalled " + b); } } } @@ -277,12 +286,12 @@ public class OsgiBoot implements OsgiBootConstants { // have already been installed... } else { if (message.contains(ALREADY_INSTALLED)) { - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.warn("Duplicate install from " + url + ": " + message); + if (logger.isLoggable(TRACE)) + logger.log(WARNING, "Duplicate install from " + url + ": " + message); } else - OsgiBootUtils.warn("Could not install bundle from " + url + ": " + message); + logger.log(WARNING, "Could not install bundle from " + url + ": " + message); } - if (OsgiBootUtils.isDebug() && !message.contains(ALREADY_INSTALLED)) + if (logger.isLoggable(TRACE) && !message.contains(ALREADY_INSTALLED)) e.printStackTrace(); } } @@ -308,7 +317,8 @@ public class OsgiBoot implements OsgiBootConstants { } } // then try all start level until a maximum - int maxStartLevel = Integer.parseInt(getProperty(InitConstants.PROP_ARGEO_OSGI_MAX_START_LEVEL, DEFAULT_MAX_START_LEVEL)); + int maxStartLevel = Integer + .parseInt(getProperty(InitConstants.PROP_ARGEO_OSGI_MAX_START_LEVEL, DEFAULT_MAX_START_LEVEL)); for (int i = 1; i <= maxStartLevel; i++) { String key = InitConstants.PROP_ARGEO_OSGI_START + "." + i; String value = getProperty(key); @@ -326,8 +336,7 @@ public class OsgiBoot implements OsgiBootConstants { doStartBundles(map); } - @Deprecated - public void startBundles(Properties properties) { + void startBundles(Properties properties) { Map map = new TreeMap<>(); // first use properties if (properties != null) { @@ -341,7 +350,10 @@ public class OsgiBoot implements OsgiBootConstants { startBundles(map); } - /** Start bundle based on keys starting with {@link InitConstants#PROP_ARGEO_OSGI_START}. */ + /** + * Start bundle based on keys starting with + * {@link InitConstants#PROP_ARGEO_OSGI_START}. + */ protected void doStartBundles(Map properties) { FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class); @@ -349,12 +361,14 @@ public class OsgiBoot implements OsgiBootConstants { int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel(); int defaultStartLevel = Integer.parseInt(getProperty(InitConstants.PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4")); int activeStartLevel = Integer.parseInt(getProperty(InitConstants.PROP_OSGI_STARTLEVEL, "6")); - if (OsgiBootUtils.isDebug()) { - OsgiBootUtils.debug("OSGi default start level: " - + getProperty(InitConstants.PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "") + ", using " + defaultStartLevel); - OsgiBootUtils.debug("OSGi active start level: " + getProperty(InitConstants.PROP_OSGI_STARTLEVEL, "") + if (logger.isLoggable(TRACE)) { + logger.log(TRACE, + "OSGi default start level: " + + getProperty(InitConstants.PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "") + ", using " + + defaultStartLevel); + logger.log(TRACE, "OSGi active start level: " + getProperty(InitConstants.PROP_OSGI_STARTLEVEL, "") + ", using " + activeStartLevel); - OsgiBootUtils.debug("Framework start level: " + frameworkStartLevel.getStartLevel() + " (initial: " + logger.log(TRACE, "Framework start level: " + frameworkStartLevel.getStartLevel() + " (initial: " + initialStartLevel + ")"); } @@ -392,23 +406,20 @@ public class OsgiBoot implements OsgiBootConstants { try { bundle.start(); } catch (BundleException e) { - OsgiBootUtils.error("Cannot mark " + bsn + " as started", e); + logger.log(ERROR, "Cannot mark " + bsn + " as started", e); } - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug(bsn + " v" + bundle.getVersion() + " starts at level " + level); + logger.log(TRACE, () -> bsn + " v" + bundle.getVersion() + " starts at level " + level); } } } - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("About to set framework start level to " + activeStartLevel + " ..."); + logger.log(TRACE, () -> "About to set framework start level to " + activeStartLevel + " ..."); frameworkStartLevel.setStartLevel(activeStartLevel, (FrameworkEvent event) -> { if (event.getType() == FrameworkEvent.ERROR) { - OsgiBootUtils.error("Start sequence failed", event.getThrowable()); + logger.log(ERROR, "Start sequence failed", event.getThrowable()); } else { - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("Framework started at level " + frameworkStartLevel.getStartLevel()); + logger.log(TRACE, () -> "Framework started at level " + frameworkStartLevel.getStartLevel()); } }); @@ -439,7 +450,8 @@ public class OsgiBoot implements OsgiBootConstants { Integer defaultStartLevel) { // default (and previously, only behaviour) - appendToStartLevels(startLevels, defaultStartLevel, properties.getOrDefault(InitConstants.PROP_ARGEO_OSGI_START, "")); + appendToStartLevels(startLevels, defaultStartLevel, + properties.getOrDefault(InitConstants.PROP_ARGEO_OSGI_START, "")); // list argeo.osgi.start.* system properties Iterator keys = properties.keySet().iterator(); @@ -514,8 +526,7 @@ public class OsgiBoot implements OsgiBootConstants { return urls; // bundlePatterns = SystemPropertyUtils.resolvePlaceholders(bundlePatterns); - if (OsgiBootUtils.isDebug()) - debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns); + logger.log(TRACE, () -> PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns); StringTokenizer st = new StringTokenizer(bundlePatterns, ","); List bundlesSets = new ArrayList(); @@ -617,8 +628,8 @@ public class OsgiBoot implements OsgiBootConstants { File[] files = baseDir.listFiles(); if (files == null) { - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.warn("Base dir " + baseDir + " has no children, exists=" + baseDir.exists() + if (logger.isLoggable(TRACE)) + logger.log(Level.WARNING, "Base dir " + baseDir + " has no children, exists=" + baseDir.exists() + ", isDirectory=" + baseDir.isDirectory()); return; } @@ -656,8 +667,8 @@ public class OsgiBoot implements OsgiBootConstants { // } } else { boolean nonDirectoryOk = matcher.matches(Paths.get(newCurrentPath)); - if (OsgiBootUtils.isDebug()) - debug(currentPath + " " + (ok ? "" : " not ") + " matched with " + pattern); + logger.log(TRACE, + () -> currentPath + " " + (ok ? "" : " not ") + " matched with " + pattern); if (nonDirectoryOk) matched.add(relativeToFullPath(base, newCurrentPath)); } @@ -730,6 +741,29 @@ public class OsgiBoot implements OsgiBootConstants { return getProperty(name, null); } + /* + * PLAIN OSGI LAUNCHER + */ + /** Launch an OSGi framework. OSGi Boot initialisation is NOT performed. */ + public static Framework defaultOsgiLaunch(Map configuration) { + Optional frameworkFactory = ServiceLoader.load(FrameworkFactory.class).findFirst(); + if (frameworkFactory.isEmpty()) + throw new IllegalStateException("No framework factory found"); + return defaultOsgiLaunch(frameworkFactory.get(), configuration); + } + + /** Launch an OSGi framework. OSGi Boot initialisation is NOT performed. */ + public static Framework defaultOsgiLaunch(FrameworkFactory frameworkFactory, Map configuration) { + // start OSGi + Framework framework = frameworkFactory.newFramework(configuration); + try { + framework.start(); + } catch (BundleException e) { + throw new IllegalStateException("Cannot start OSGi framework", e); + } + return framework; + } + /* * BEAN METHODS */ diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootConstants.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiBootConstants.java deleted file mode 100644 index e45f82689..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootConstants.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.argeo.init.osgi; - -public interface OsgiBootConstants { - -} diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootDiagnostics.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiBootDiagnostics.java index b56b6b070..074ecedb6 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootDiagnostics.java +++ b/org.argeo.init/src/org/argeo/init/osgi/OsgiBootDiagnostics.java @@ -1,5 +1,8 @@ package org.argeo.init.osgi; +import static java.lang.System.Logger.Level.WARNING; + +import java.lang.System.Logger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -14,8 +17,9 @@ import org.osgi.framework.ServiceReference; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; -@SuppressWarnings("deprecation") class OsgiBootDiagnostics { + private final static Logger logger = System.getLogger(OsgiBootDiagnostics.class.getName()); + private final BundleContext bundleContext; public OsgiBootDiagnostics(BundleContext bundleContext) { @@ -41,7 +45,7 @@ class OsgiBootDiagnostics { } if (unresolvedBundles.size() != 0) { - OsgiBootUtils.warn("Unresolved bundles " + unresolvedBundles); + logger.log(WARNING, "Unresolved bundles " + unresolvedBundles); } // try to start unresolved bundles in order to trigger diagnostics diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootUtils.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiBootUtils.java deleted file mode 100644 index a782ac37b..000000000 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBootUtils.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.argeo.init.osgi; - -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.StringTokenizer; - -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleException; -import org.osgi.framework.launch.Framework; -import org.osgi.framework.launch.FrameworkFactory; - -/** Utilities, mostly related to logging. */ -public class OsgiBootUtils { - private final static Logger logger = System.getLogger(OsgiBootUtils.class.getName()); - - public static void info(Object obj) { - logger.log(Level.INFO, () -> Objects.toString(obj)); - } - - public static void debug(Object obj) { - logger.log(Level.TRACE, () -> Objects.toString(obj)); - } - - public static void warn(Object obj) { - logger.log(Level.WARNING, () -> Objects.toString(obj)); - } - - public static void error(Object obj, Throwable e) { - logger.log(Level.ERROR, () -> Objects.toString(obj), e); - } - - public static boolean isDebug() { - return logger.isLoggable(Level.TRACE); - } - - public static String stateAsString(int state) { - switch (state) { - case Bundle.UNINSTALLED: - return "UNINSTALLED"; - case Bundle.INSTALLED: - return "INSTALLED"; - case Bundle.RESOLVED: - return "RESOLVED"; - case Bundle.STARTING: - return "STARTING"; - case Bundle.ACTIVE: - return "ACTIVE"; - case Bundle.STOPPING: - return "STOPPING"; - default: - return Integer.toString(state); - } - } - - /** - * @return ==0: versions are identical, <0: tested version is newer, >0: - * currentVersion is newer. - */ - public static int compareVersions(String currentVersion, String testedVersion) { - List cToks = new ArrayList(); - StringTokenizer cSt = new StringTokenizer(currentVersion, "."); - while (cSt.hasMoreTokens()) - cToks.add(cSt.nextToken()); - List tToks = new ArrayList(); - StringTokenizer tSt = new StringTokenizer(currentVersion, "."); - while (tSt.hasMoreTokens()) - tToks.add(tSt.nextToken()); - - int comp = 0; - comp: for (int i = 0; i < cToks.size(); i++) { - if (tToks.size() <= i) { - // equals until then, tested shorter - comp = 1; - break comp; - } - - String c = (String) cToks.get(i); - String t = (String) tToks.get(i); - - try { - int cInt = Integer.parseInt(c); - int tInt = Integer.parseInt(t); - if (cInt == tInt) - continue comp; - else { - comp = (cInt - tInt); - break comp; - } - } catch (NumberFormatException e) { - if (c.equals(t)) - continue comp; - else { - comp = c.compareTo(t); - break comp; - } - } - } - - if (comp == 0 && tToks.size() > cToks.size()) { - // equals until then, current shorter - comp = -1; - } - - return comp; - } - - public static Framework launch(Map configuration) { - Optional frameworkFactory = ServiceLoader.load(FrameworkFactory.class).findFirst(); - if (frameworkFactory.isEmpty()) - throw new IllegalStateException("No framework factory found"); - return launch(frameworkFactory.get(), configuration); - } - - /** Launch an OSGi framework. */ - public static Framework launch(FrameworkFactory frameworkFactory, Map configuration) { - // start OSGi - Framework framework = frameworkFactory.newFramework(configuration); - try { - framework.start(); - } catch (BundleException e) { - throw new IllegalStateException("Cannot start OSGi framework", e); - } - return framework; - } - - @Deprecated - public static Map equinoxArgsToConfiguration(String[] args) { - // FIXME implement it - return new HashMap<>(); - } - -} diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiBuilder.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiBuilder.java index 6eed6db53..d89535e03 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiBuilder.java +++ b/org.argeo.init/src/org/argeo/init/osgi/OsgiBuilder.java @@ -1,5 +1,9 @@ package org.argeo.init.osgi; +import static java.lang.System.Logger.Level.ERROR; +import static java.lang.System.Logger.Level.TRACE; + +import java.lang.System.Logger; import java.lang.reflect.Method; import java.net.URI; import java.util.ArrayList; @@ -26,6 +30,8 @@ import org.osgi.util.tracker.ServiceTracker; /** OSGi builder, focusing on ease of use for scripting. */ public class OsgiBuilder { + private final static Logger logger = System.getLogger(OsgiBuilder.class.getName()); + private final static String PROP_HTTP_PORT = "org.osgi.service.http.port"; private final static String PROP_HTTPS_PORT = "org.osgi.service.https.port"; private final static String PROP_OSGI_CLEAN = "osgi.clean"; @@ -39,21 +45,22 @@ public class OsgiBuilder { public OsgiBuilder() { // configuration.put("osgi.clean", "true"); - configuration.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, System.getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA)); - configuration.put(InitConstants.PROP_OSGI_INSTANCE_AREA, System.getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA)); + configuration.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, + System.getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA)); + configuration.put(InitConstants.PROP_OSGI_INSTANCE_AREA, + System.getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA)); configuration.put(PROP_OSGI_CLEAN, System.getProperty(PROP_OSGI_CLEAN)); } public Framework launch() { // start OSGi - framework = OsgiBootUtils.launch(configuration); + framework = OsgiBoot.defaultOsgiLaunch(configuration); BundleContext bc = framework.getBundleContext(); String osgiData = bc.getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA); // String osgiConf = bc.getProperty(OsgiBoot.CONFIGURATION_AREA_PROP); String osgiConf = framework.getDataFile("").getAbsolutePath(); - if (OsgiBootUtils.isDebug()) - OsgiBootUtils.debug("OSGi starting - data: " + osgiData + " conf: " + osgiConf); + logger.log(TRACE, () -> "OSGi starting - data: " + osgiData + " conf: " + osgiConf); OsgiBoot osgiBoot = new OsgiBoot(framework.getBundleContext()); if (distributionBundles.isEmpty()) { @@ -179,7 +186,7 @@ public class OsgiBuilder { try { return st.waitForService(timeout); } catch (InterruptedException e) { - OsgiBootUtils.error("Interrupted", e); + logger.log(ERROR, "Interrupted", e); return null; } finally { st.close(); diff --git a/org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeContext.java b/org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeContext.java index c35046b20..b7079f60e 100644 --- a/org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeContext.java +++ b/org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeContext.java @@ -1,11 +1,12 @@ package org.argeo.init.osgi; import java.io.Serializable; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; import java.lang.System.LoggerFinder; import java.util.Collections; import java.util.Hashtable; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.ServiceLoader; import java.util.concurrent.Flow; @@ -22,9 +23,16 @@ import org.osgi.framework.launch.FrameworkFactory; /** An OSGi runtime context. */ public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable { + private final static Logger logger = System.getLogger(OsgiRuntimeContext.class.getName()); + + private final static long STOP_FOR_UPDATE_TIMEOUT = 60 * 1000; + private final static long CLOSE_TIMEOUT = 60 * 1000; + + private final static String SYMBOLIC_NAME_FELIX_SCR = "org.apache.felix.scr"; + private Map config; private Framework framework; - private OsgiBoot osgiBoot; +// private OsgiBoot osgiBoot; /** * Constructor to use when the runtime context will create the OSGi @@ -44,11 +52,17 @@ public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable { @Override public void run() { - ServiceLoader sl = ServiceLoader.load(FrameworkFactory.class); - Optional opt = sl.findFirst(); - if (opt.isEmpty()) - throw new IllegalStateException("Cannot find OSGi framework"); - framework = opt.get().newFramework(config); + if (framework != null && framework.getState() >= Framework.STARTING) + throw new IllegalStateException("OSGi framework is already started"); + + if (framework == null) { + ServiceLoader sl = ServiceLoader.load(FrameworkFactory.class); + Optional opt = sl.findFirst(); + if (opt.isEmpty()) + throw new IllegalStateException("Cannot find OSGi framework"); + framework = opt.get().newFramework(config); + } + try { framework.start(); BundleContext bundleContext = framework.getBundleContext(); @@ -58,7 +72,7 @@ public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable { } } - public void start(BundleContext bundleContext) { + protected void start(BundleContext bundleContext) { // preferences // SystemRootPreferences systemRootPreferences = ThinPreferencesFactory.getInstance().getSystemRootPreferences(); // bundleContext.registerService(AbstractPreferences.class, systemRootPreferences, new Hashtable<>()); @@ -80,17 +94,38 @@ public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable { bundleContext.registerService(Flow.Publisher.class, supplier.get(), new Hashtable<>(Collections.singletonMap(Constants.SERVICE_PID, "argeo.logging.publisher"))); } - osgiBoot = new OsgiBoot(bundleContext); + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); osgiBoot.bootstrap(config); - } public void update() { - Objects.requireNonNull(osgiBoot); - osgiBoot.update(); + stop(); + try { + waitForStop(STOP_FOR_UPDATE_TIMEOUT); + } catch (InterruptedException e) { + logger.log(Level.TRACE, "Wait for stop interrupted", e); + } + run(); + + // TODO Optimise with OSGi mechanisms (e.g. framework.update()) +// if (osgiBoot != null) { +// Objects.requireNonNull(osgiBoot); +// osgiBoot.update(); +// } } - public void stop(BundleContext bundleContext) { + protected void stop() { + if (framework == null) + return; + stop(framework.getBundleContext()); + try { + framework.stop(); + } catch (BundleException e) { + throw new IllegalStateException("Cannot stop OSGi framework", e); + } + } + + protected void stop(BundleContext bundleContext) { // if (loggingConfigurationSr != null) // try { // loggingConfigurationSr.unregister(); @@ -108,26 +143,41 @@ public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable { @Override public void waitForStop(long timeout) throws InterruptedException { if (framework == null) - throw new IllegalStateException("Framework is not initialised"); + return; framework.waitForStop(timeout); } public void close() throws Exception { + if (framework == null) + return; +// Bundle scrBundle = osgiBoot.getBundlesBySymbolicName().get(); +// if (scrBundle != null && scrBundle.getState() > Bundle.RESOLVED) { +// scrBundle.stop(); +// while (!(scrBundle.getState() <= Bundle.RESOLVED)) { +// Thread.sleep(500); +// } +// Thread.sleep(1000); +// } + // TODO make shutdown of dynamic service more robust - Bundle scrBundle = osgiBoot.getBundlesBySymbolicName().get("org.apache.felix.scr"); - if (scrBundle != null) { - scrBundle.stop(); - while (!(scrBundle.getState() <= Bundle.RESOLVED)) { - Thread.sleep(500); + for (Bundle scrBundle : framework.getBundleContext().getBundles()) { + if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) { + if (scrBundle.getState() > Bundle.RESOLVED) { + scrBundle.stop(); + while (!(scrBundle.getState() <= Bundle.RESOLVED)) { + Thread.sleep(100); + } + Thread.sleep(100); + } } - Thread.sleep(1000); } - stop(framework.getBundleContext()); - if (framework != null) - framework.stop(); - + stop(); + waitForStop(CLOSE_TIMEOUT); + framework = null; +// osgiBoot = null; + config.clear(); } public Framework getFramework() { diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebApp.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebApp.java index 67fa5ceac..c4e9ca749 100644 --- a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebApp.java +++ b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebApp.java @@ -106,7 +106,7 @@ public class CmsWebApp implements ApplicationConfiguration, ExceptionHandler, Cm return entryPoint; }, properties); if (log.isDebugEnabled()) - log.info("Added web entry point " + (contextName != null ? "/" + contextName : "") + entryPointName); + log.debug("Added web entry point " + (contextName != null ? "/" + contextName : "") + entryPointName); } // if (log.isDebugEnabled()) // log.debug("Published CMS web app /" + (contextName != null ? contextName : "")); @@ -150,8 +150,7 @@ public class CmsWebApp implements ApplicationConfiguration, ExceptionHandler, Cm rwtAppReg.unregister(); if (bundleContext != null) { rwtAppReg = bundleContext.registerService(ApplicationConfiguration.class, this, regProps); - if (log.isDebugEnabled()) - log.debug("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ..."); + log.info("Publishing CMS web app /" + (contextName != null ? contextName : "") + " ..."); } }