Introduce runtime manager
[lgpl/argeo-commons.git] / org.argeo.init / src / org / argeo / init / Service.java
index cab85d02ff3e8eefa19317916ebf0de3f286af30..b080a7513b97a3b10c07870eb3ec328af056f2d6 100644 (file)
@@ -3,13 +3,18 @@ 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.init.logging.ThinLoggerFinder;
 import org.argeo.init.osgi.OsgiBoot;
@@ -19,10 +24,14 @@ import org.argeo.init.osgi.OsgiRuntimeContext;
 public class Service {
        private final static Logger logger = System.getLogger(Service.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<Runnable> postStart = Collections.synchronizedList(new ArrayList<>());
+
        protected Service(String[] args) {
        }
 
@@ -51,7 +60,7 @@ public class Service {
 
                if (configArea != null) {
                        Path configAreaPath = Paths.get(configArea);
-                       Path additionalSystemPropertiesPath = configAreaPath.resolve("system.properties");
+                       Path additionalSystemPropertiesPath = configAreaPath.resolve(FILE_SYSTEM_PROPERTIES);
                        if (Files.exists(additionalSystemPropertiesPath)) {
                                Properties properties = new Properties();
                                try (InputStream in = Files.newInputStream(additionalSystemPropertiesPath)) {
@@ -70,6 +79,8 @@ public class Service {
                                                                        + 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();
@@ -79,6 +90,27 @@ public class Service {
                Map<String, String> 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 OsgiBoot.PROP_OSGI_CONFIGURATION_AREA:
+                       case OsgiBoot.PROP_OSGI_SHARED_CONFIGURATION_AREA:
+                       case OsgiBoot.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)
@@ -92,11 +124,25 @@ public class Service {
                                OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext(config);
                                osgiRuntimeContext.run();
                                Service.runtimeContext = osgiRuntimeContext;
+                               for (Runnable run : postStart) {
+                                       try {
+                                               run.run();
+                                       } catch (Exception e) {
+                                               logger.log(Level.ERROR, "Cannot run post start callback " + run, e);
+                                       }
+                               }
                                Service.runtimeContext.waitForStop(0);
-                       } catch (NoClassDefFoundError e) {
+                       } catch (NoClassDefFoundError noClassDefFoundE) {
                                StaticRuntimeContext staticRuntimeContext = new StaticRuntimeContext((Map<String, String>) config);
                                staticRuntimeContext.run();
                                Service.runtimeContext = staticRuntimeContext;
+                               for (Runnable run : postStart) {
+                                       try {
+                                               run.run();
+                                       } catch (Exception e) {
+                                               logger.log(Level.ERROR, "Cannot run post start callback " + run, e);
+                                       }
+                               }
                                Service.runtimeContext.waitForStop(0);
                        }
                } catch (Exception e) {
@@ -106,7 +152,13 @@ public class Service {
                logger.log(Logger.Level.DEBUG, "Argeo Init stopped with PID " + pid);
        }
 
+       /** The root runtime context in this JVM. */
        public static RuntimeContext getRuntimeContext() {
                return runtimeContext;
        }
+
+       /** Add a post-start call back to be run after the runtime has been started. */
+       public static void addPostStart(Runnable runnable) {
+               postStart.add(runnable);
+       }
 }