X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=blobdiff_plain;f=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Finit%2FServiceMain.java;fp=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Finit%2FServiceMain.java;h=ca8ba3a7f71191626f684ff2fd29879242fd0755;hp=0000000000000000000000000000000000000000;hb=b95462873703848193e56fcbe997693630db6121;hpb=55d88fba80cec198a0f11ba7545e19878c51fc5e diff --git a/org.argeo.init/src/org/argeo/init/ServiceMain.java b/org.argeo.init/src/org/argeo/init/ServiceMain.java new file mode 100644 index 000000000..ca8ba3a7f --- /dev/null +++ b/org.argeo.init/src/org/argeo/init/ServiceMain.java @@ -0,0 +1,159 @@ +package org.argeo.init; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.TreeMap; + +import org.argeo.api.init.InitConstants; +import org.argeo.init.logging.ThinLoggerFinder; +import org.argeo.init.osgi.OsgiRuntimeContext; +import org.argeo.internal.init.InternalState; + +/** Configures and launches a single runtime, typically as a systemd service. */ +public class ServiceMain { + private final static Logger logger = System.getLogger(ServiceMain.class.getName()); + + final static String FILE_SYSTEM_PROPERTIES = "system.properties"; + + public final static String PROP_ARGEO_INIT_MAIN = "argeo.init.main"; + +// private static RuntimeContext runtimeContext = null; + + private static List postStart = Collections.synchronizedList(new ArrayList<>()); + + protected ServiceMain(String[] args) { + } + + public static void main(String[] args) { + final long pid = ProcessHandle.current().pid(); + logger.log(Logger.Level.DEBUG, () -> "Argeo Init starting with PID " + pid); + + // shutdown on exit + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + if (InternalState.getMainRuntimeContext() != null) { + InternalState.getMainRuntimeContext().close(); + InternalState.getMainRuntimeContext().waitForStop(0); + } + } catch (Exception e) { + e.printStackTrace(); + Runtime.getRuntime().halt(1); + } + }, "Runtime shutdown")); + + // TODO use args as well + String dataArea = System.getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA); + String stateArea = System.getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA); + String configArea = System.getProperty(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA); + + if (configArea != null) { + Path configAreaPath = Paths.get(configArea); + Path additionalSystemPropertiesPath = configAreaPath.resolve(FILE_SYSTEM_PROPERTIES); + if (Files.exists(additionalSystemPropertiesPath)) { + Properties properties = new Properties(); + try (InputStream in = Files.newInputStream(additionalSystemPropertiesPath)) { + properties.load(in); + } catch (IOException e) { + logger.log(Logger.Level.ERROR, + "Cannot load additional system properties " + additionalSystemPropertiesPath, e); + } + + for (Object key : properties.keySet()) { + String currentValue = System.getProperty(key.toString()); + String value = properties.getProperty(key.toString()); + if (currentValue != null) { + if (!Objects.equals(value, currentValue)) + logger.log(Logger.Level.WARNING, "System property " + key + " already set with value " + + currentValue + " instead of " + value + ". Ignoring new value."); + } else { + System.setProperty(key.toString(), value); + logger.log(Logger.Level.TRACE, () -> "Added " + key + "=" + value + + " to system properties, from " + additionalSystemPropertiesPath.getFileName()); + } + } + ThinLoggerFinder.reloadConfiguration(); + } + } + + Map config = new HashMap<>(); + config.put(PROP_ARGEO_INIT_MAIN, "true"); + + // add OSGi system properties to the configuration + sysprops: for (Object key : new TreeMap<>(System.getProperties()).keySet()) { + String keyStr = key.toString(); + switch (keyStr) { + case InitConstants.PROP_OSGI_CONFIGURATION_AREA: + case InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA: + case InitConstants.PROP_OSGI_INSTANCE_AREA: + // we should already have dealt with those + continue sysprops; + default: + } + + if (keyStr.startsWith("osgi.") || keyStr.startsWith("org.osgi.") || keyStr.startsWith("eclipse.") + || keyStr.startsWith("org.eclipse.equinox.") || keyStr.startsWith("felix.")) { + String value = System.getProperty(keyStr); + config.put(keyStr, value); + logger.log(Logger.Level.TRACE, + () -> "Added " + key + "=" + value + " to configuration, from system properties"); + } + } + + try { + try { + if (stateArea != null) + config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, stateArea); + if (configArea != null) + config.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA, configArea); + if (dataArea != null) + config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, dataArea); + // config.put(OsgiBoot.PROP_OSGI_USE_SYSTEM_PROPERTIES, "true"); + + OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext(config); + osgiRuntimeContext.run(); + InternalState.setMainRuntimeContext(osgiRuntimeContext); + for (Runnable run : postStart) { + try { + run.run(); + } catch (Exception e) { + logger.log(Level.ERROR, "Cannot run post start callback " + run, e); + } + } + InternalState.getMainRuntimeContext().waitForStop(0); + } catch (NoClassDefFoundError noClassDefFoundE) { + StaticRuntimeContext staticRuntimeContext = new StaticRuntimeContext((Map) config); + staticRuntimeContext.run(); + InternalState.setMainRuntimeContext(staticRuntimeContext); + for (Runnable run : postStart) { + try { + run.run(); + } catch (Exception e) { + logger.log(Level.ERROR, "Cannot run post start callback " + run, e); + } + } + InternalState.getMainRuntimeContext().waitForStop(0); + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + logger.log(Logger.Level.DEBUG, "Argeo Init stopped with PID " + pid); + } + + /** Add a post-start call back to be run after the runtime has been started. */ + public static void addPostStart(Runnable runnable) { + postStart.add(runnable); + } +}