Improve init
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 22 Jul 2022 06:48:55 +0000 (08:48 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 22 Jul 2022 06:48:55 +0000 (08:48 +0200)
org.argeo.init/src/org/argeo/init/Service.java
org.argeo.init/src/org/argeo/init/logging/ThinLoggerFinder.java
org.argeo.init/src/org/argeo/init/logging/ThinLogging.java
org.argeo.init/src/org/argeo/init/osgi/Activator.java
org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java
org.argeo.init/src/org/argeo/init/osgi/OsgiBootUtils.java
sdk/deploy/argeo-init/usr/lib/systemd/system/argeo@.service

index 9dcea49d2d6199cad72b9696191de85ecbd69f53..aa9494c91591605e41f2061a8864d158cdc48d51 100644 (file)
@@ -1,31 +1,34 @@
 package org.argeo.init;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.System.Logger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
 
+import org.argeo.init.logging.ThinLoggerFinder;
+import org.argeo.init.osgi.OsgiBoot;
 import org.argeo.init.osgi.OsgiRuntimeContext;
 
 /** Configure and launch an Argeo service. */
-public class Service implements Runnable, AutoCloseable {
-       private final static Logger log = System.getLogger(Service.class.getName());
+public class Service {
+       private final static Logger logger = System.getLogger(Service.class.getName());
+
+       public final static String PROP_ARGEO_INIT_MAIN = "argeo.init.main";
 
        private static RuntimeContext runtimeContext = null;
 
        protected Service(String[] args) {
        }
 
-       @Override
-       public void run() {
-       }
-
-       @Override
-       public void close() throws Exception {
-       }
-
        public static void main(String[] args) {
-               long pid = ProcessHandle.current().pid();
-               log.log(Logger.Level.DEBUG, "Argeo Init starting with PID " + pid);
+               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(() -> {
@@ -41,15 +44,52 @@ public class Service implements Runnable, AutoCloseable {
                        }
                }, "Runtime shutdown"));
 
+               // TODO use args as well
+               String dataArea = System.getProperty(OsgiBoot.PROP_OSGI_INSTANCE_AREA);
+               String stateArea = System.getProperty(OsgiBoot.PROP_OSGI_CONFIGURATION_AREA);
+               String configArea = System.getProperty(OsgiBoot.PROP_OSGI_SHARED_CONFIGURATION_AREA);
+
+               if (configArea != null) {
+                       Path configAreaPath = Paths.get(configArea);
+                       Path additionalSystemPropertiesPath = configAreaPath.resolve("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);
+                                       }
+                               }
+                               ThinLoggerFinder.reloadConfiguration();
+                       }
+               }
+
                Map<String, String> config = new HashMap<>();
-               config.put("osgi.framework.useSystemProperties", "true");
-//             for (Object key : System.getProperties().keySet()) {
-//                     config.put(key.toString(), System.getProperty(key.toString()));
-//                     log.log(Logger.Level.DEBUG, key + "=" + System.getProperty(key.toString()));
-//             }
+               config.put(PROP_ARGEO_INIT_MAIN, "true");
+
                try {
                        try {
-                               OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext((Map<String, String>) config);
+                               if (stateArea != null)
+                                       config.put(OsgiBoot.PROP_OSGI_CONFIGURATION_AREA, stateArea);
+                               if (configArea != null)
+                                       config.put(OsgiBoot.PROP_OSGI_SHARED_CONFIGURATION_AREA, configArea);
+                               if (dataArea != null)
+                                       config.put(OsgiBoot.PROP_OSGI_INSTANCE_AREA, dataArea);
+                               // config.put(OsgiBoot.PROP_OSGI_USE_SYSTEM_PROPERTIES, "true");
+
+                               OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext(config);
                                osgiRuntimeContext.run();
                                Service.runtimeContext = osgiRuntimeContext;
                                Service.runtimeContext.waitForStop(0);
@@ -63,10 +103,9 @@ public class Service implements Runnable, AutoCloseable {
                        e.printStackTrace();
                        System.exit(1);
                }
-               log.log(Logger.Level.DEBUG, "Argeo Init stopped with PID " + pid);
+               logger.log(Logger.Level.DEBUG, "Argeo Init stopped with PID " + pid);
        }
 
-       
        public static RuntimeContext getRuntimeContext() {
                return runtimeContext;
        }
index 47cb14655e45e78b4813159577273ca36232b10a..e60d22fba1061238e20da6b0071afdfdcf03ca7a 100644 (file)
@@ -32,7 +32,13 @@ public class ThinLoggerFinder extends LoggerFinder {
 
        private static void init() {
                logging = new ThinLogging();
+               reloadConfiguration();
+       }
 
+       /** Reload configuration form system properties */
+       public static void reloadConfiguration() {
+               if (logging == null)
+                       return;
                Map<String, Object> configuration = new HashMap<>();
                for (Object key : System.getProperties().keySet()) {
                        Objects.requireNonNull(key);
index 85ed9eb4fe1a79e24dd4efa92be26f532ddd878b..e03b179a35bc947f8612266555e34a62a6c7bc83 100644 (file)
@@ -37,8 +37,12 @@ class ThinLogging implements Consumer<Map<String, Object>> {
        final static String DEFAULT_LEVEL_PROPERTY = "log";
        final static String LEVEL_PROPERTY_PREFIX = DEFAULT_LEVEL_PROPERTY + ".";
 
-       final static String JOURNALD_PROPERTY = "argeo.logging.journald";
-       final static String CALL_LOCATION_PROPERTY = "argeo.logging.callLocation";
+       final static String PROP_ARGEO_LOGGING_SYNCHRONOUS = "argeo.logging.synchronous";
+       final static String PROP_ARGEO_LOGGING_JOURNALD = "argeo.logging.journald";
+       final static String PROP_ARGEO_LOGGING_CALL_LOCATION = "argeo.logging.callLocation";
+
+       final static String ENV_INVOCATION_ID = "INVOCATION_ID";
+       final static String ENV_GIO_LAUNCHED_DESKTOP_FILE_PID = "GIO_LAUNCHED_DESKTOP_FILE_PID";
 
        private final static AtomicLong nextEntry = new AtomicLong(0l);
 
@@ -56,7 +60,7 @@ class ThinLogging implements Consumer<Map<String, Object>> {
        private final boolean journald;
        private final Level callLocationLevel;
 
-       private boolean synchronous = true;
+       private boolean synchronous = Boolean.parseBoolean(System.getProperty(PROP_ARGEO_LOGGING_SYNCHRONOUS));
 
        ThinLogging() {
 //             executor = Executors.newCachedThreadPool((r) -> {
@@ -78,7 +82,7 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                }
 
                // initial default level
-               levels.put("", Level.WARNING);
+               levels.put(DEFAULT_LEVEL_NAME, Level.WARNING);
 
                // Logging system config
                // journald
@@ -88,13 +92,13 @@ class ThinLogging implements Consumer<Map<String, Object>> {
 //                     System.out.println(key + "=" + env.get(key));
 //             }
 
-               String journaldStr = System.getProperty(JOURNALD_PROPERTY, "auto");
+               String journaldStr = System.getProperty(PROP_ARGEO_LOGGING_JOURNALD, "auto");
                switch (journaldStr) {
                case "auto":
-                       String systemdInvocationId = System.getenv("INVOCATION_ID");
+                       String systemdInvocationId = System.getenv(ENV_INVOCATION_ID);
                        if (systemdInvocationId != null) {// in systemd
-                               // check whether we are indirectly in a desktop app (e.g. eclipse)
-                               String desktopFilePid = System.getenv("GIO_LAUNCHED_DESKTOP_FILE_PID");
+                               // check whether we are indirectly in a desktop app (typically an IDE)
+                               String desktopFilePid = System.getenv(ENV_GIO_LAUNCHED_DESKTOP_FILE_PID);
                                if (desktopFilePid != null) {
                                        Long javaPid = ProcessHandle.current().pid();
                                        if (!javaPid.toString().equals(desktopFilePid)) {
@@ -117,10 +121,10 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                        break;
                default:
                        throw new IllegalArgumentException(
-                                       "Unsupported value '" + journaldStr + "' for property " + JOURNALD_PROPERTY);
+                                       "Unsupported value '" + journaldStr + "' for property " + PROP_ARGEO_LOGGING_JOURNALD);
                }
 
-               String callLocationStr = System.getProperty(CALL_LOCATION_PROPERTY, Level.WARNING.getName());
+               String callLocationStr = System.getProperty(PROP_ARGEO_LOGGING_CALL_LOCATION, Level.WARNING.getName());
                callLocationLevel = Level.valueOf(callLocationStr);
        }
 
@@ -136,7 +140,7 @@ class ThinLogging implements Consumer<Map<String, Object>> {
 
                publisher.close();
                try {
-                       // we ait a bit in order to make sure all messages are flushed
+                       // we wait a bit in order to make sure all messages are flushed
                        // TODO synchronize more efficiently
                        // executor.awaitTermination(300, TimeUnit.MILLISECONDS);
                        ForkJoinPool.commonPool().awaitTermination(300, TimeUnit.MILLISECONDS);
@@ -148,28 +152,13 @@ class ThinLogging implements Consumer<Map<String, Object>> {
        private Level computeApplicableLevel(String name) {
                Map.Entry<String, Level> entry = levels.floorEntry(name);
                assert entry != null;
-               return entry.getValue();
+               if (name.startsWith(entry.getKey()))
+                       return entry.getValue();
+               else
+                       return levels.get(DEFAULT_LEVEL_NAME);// default
 
        }
 
-//     private boolean isLoggable(String name, Level level) {
-//             Objects.requireNonNull(name);
-//             Objects.requireNonNull(level);
-//
-//             if (updatingConfiguration) {
-//                     synchronized (levels) {
-//                             try {
-//                                     levels.wait();
-//                                     // TODO make exit more robust
-//                             } catch (InterruptedException e) {
-//                                     throw new IllegalStateException(e);
-//                             }
-//                     }
-//             }
-//
-//             return level.getSeverity() >= computeApplicableLevel(name).getSeverity();
-//     }
-
        public Logger getLogger(String name, Module module) {
                if (!loggers.containsKey(name)) {
                        ThinLogger logger = new ThinLogger(name, computeApplicableLevel(name));
@@ -222,7 +211,6 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                        updatingConfiguration = false;
                        levels.notifyAll();
                }
-
        }
 
        Flow.Publisher<Map<String, Serializable>> getLogEntryPublisher() {
@@ -445,6 +433,8 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                private PrintStream err;
                private int writeToErrLevel = Level.WARNING.getSeverity();
 
+               private Subscription subscription;
+
                protected PrintStreamSubscriber() {
                        this(System.out, System.err);
                }
@@ -460,7 +450,8 @@ class ThinLogging implements Consumer<Map<String, Object>> {
 
                @Override
                public void onSubscribe(Subscription subscription) {
-                       subscription.request(Long.MAX_VALUE);
+                       this.subscription = subscription;
+                       this.subscription.request(1);
                }
 
                @Override
@@ -471,6 +462,7 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                                out.print(toPrint(item));
                        }
                        // TODO flush for journald?
+                       this.subscription.request(1);
                }
 
                @Override
@@ -532,10 +524,9 @@ class ThinLogging implements Consumer<Map<String, Object>> {
                protected String toPrint(Map<String, Serializable> logEntry) {
                        StringBuilder sb = new StringBuilder();
                        StringTokenizer st = new StringTokenizer((String) logEntry.get(KEY_MSG), "\r\n");
-                       assert st.hasMoreTokens();
 
                        // first line
-                       String firstLine = st.nextToken();
+                       String firstLine = st.hasMoreTokens() ? st.nextToken() : "";
                        sb.append(firstLinePrefix(logEntry));
                        sb.append(firstLine);
                        sb.append(firstLineSuffix(logEntry));
index 518751f91e655f27bcadda1e4ea02e21d0e056fa..b85b248b9e17c94f01be20070cb86e69f3a79dd4 100644 (file)
@@ -4,6 +4,7 @@ import java.lang.System.Logger;
 import java.lang.System.Logger.Level;
 import java.util.Objects;
 
+import org.argeo.init.Service;
 import org.argeo.init.logging.ThinLoggerFinder;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -18,36 +19,45 @@ public class Activator implements BundleActivator {
                // must be called first
                ThinLoggerFinder.lazyInit();
        }
-       private Logger logger = System.getLogger(Activator.class.getName());
+       private final static Logger logger = System.getLogger(Activator.class.getName());
 
        private Long checkpoint = null;
 
+       private boolean argeoInit = false;
        /** Not null if we created it ourselves. */
        private OsgiRuntimeContext runtimeContext;
 
        public void start(final BundleContext bundleContext) throws Exception {
-               if (runtimeContext == null) {
-                       runtimeContext = new OsgiRuntimeContext(bundleContext);
-               }
-               logger.log(Level.DEBUG, () -> "Argeo init via OSGi activator");
-
-               // admin thread
+               // The OSGi runtime was created by us, and therefore already initialized
+               argeoInit = Boolean.parseBoolean(bundleContext.getProperty(Service.PROP_ARGEO_INIT_MAIN));
+               if (!argeoInit) {
+                       if (runtimeContext == null) {
+                               runtimeContext = new OsgiRuntimeContext(bundleContext);
+                               logger.log(Level.DEBUG, () -> "Argeo init via OSGi activator");
+                       }
+
+                       // admin thread
 //             Thread adminThread = new AdminThread(bundleContext);
 //             adminThread.start();
 
-               // bootstrap
+                       // bootstrap
 //             OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
-               if (checkpoint == null) {
+                       if (checkpoint == null) {
 //                     osgiBoot.bootstrap();
-                       checkpoint = System.currentTimeMillis();
-               } else {
-                       runtimeContext.update();
-                       checkpoint = System.currentTimeMillis();
+                               checkpoint = System.currentTimeMillis();
+                       } else {
+                               runtimeContext.update();
+                               checkpoint = System.currentTimeMillis();
+                       }
                }
        }
 
        public void stop(BundleContext context) throws Exception {
-               Objects.nonNull(runtimeContext);
-               runtimeContext.stop(context);
+               if (!argeoInit) {
+                       Objects.nonNull(runtimeContext);
+                       runtimeContext.stop(context);
+                       runtimeContext = null;
+               }
        }
+
 }
index 353e39c798ed2e69c23852a46dc6a49f474ab717..d9f3b3c7bf76bc5e9cdf919fd68535dc4d8d0655 100644 (file)
@@ -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;
@@ -39,54 +37,45 @@ import org.osgi.framework.wiring.FrameworkWiring;
  * methods, configured via properties.
  */
 public class OsgiBoot implements OsgiBootConstants {
-       public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start";
-       public final static String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources";
+       final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start";
+       final static String PROP_ARGEO_OSGI_MAX_START_LEVEL = "argeo.osgi.maxStartLevel";
+       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";
 
-       public final static String DEFAULT_BASE_URL = "reference:file:";
-       // public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**";
+       final static String DEFAULT_BASE_URL = "reference:file:";
+       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 +89,22 @@ 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 {
-                                       provisioningManager.registerSource(source);
+                                       provisioningManager.registerSource(source + queryPart);
                                }
                        }
                }
@@ -135,46 +126,60 @@ public class OsgiBoot implements OsgiBootConstants {
                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.");
-                               }
-                       }
+//                     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 {
+//                                                     if (value.startsWith("/"))
+//                                                             value = "file://" + value;
+//                                                     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();
+
+                       // 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");
@@ -313,34 +318,68 @@ 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 system properties.
+//      * 
+//      * @see OsgiBoot#doStartBundles(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<String, String> properties) {
+               Map<String, String> 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<String, String> 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<String, String> properties) {
+       protected void doStartBundles(Map<String, String> properties) {
                FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class);
 
                // default and active start levels from System properties
@@ -725,10 +764,6 @@ public class OsgiBoot implements OsgiBootConstants {
                }
        }
 
-       protected void matchFile() {
-
-       }
-
        /*
         * LOW LEVEL UTILITIES
         */
@@ -807,9 +842,9 @@ public class OsgiBoot implements OsgiBootConstants {
                return bundleContext;
        }
 
-       public String getLocalCache() {
-               return localCache;
-       }
+//     public String getLocalCache() {
+//             return localCache;
+//     }
 
        // public void setDefaultTimeout(long defaultTimeout) {
        // this.defaultTimeout = defaultTimeout;
index e0b2f155105c83aa7402fa8cadfbd32ccc2dfb2b..a782ac37b078bf7835489df5cb69144d834c89e4 100644 (file)
@@ -20,42 +20,23 @@ import org.osgi.framework.launch.FrameworkFactory;
 public class OsgiBootUtils {
        private final static Logger logger = System.getLogger(OsgiBootUtils.class.getName());
 
-//     /** ISO8601 (as per log4j) and difference to UTC */
-//     private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS Z");
-
-//     static boolean debug = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_DEBUG) == null ? false
-//                     : !System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_DEBUG).trim().equals("false");
-
-       @Deprecated
        public static void info(Object obj) {
-//             System.out.println("# OSGiBOOT      # " + dateFormat.format(new Date()) + " # " + obj);
                logger.log(Level.INFO, () -> Objects.toString(obj));
        }
 
-       @Deprecated
        public static void debug(Object obj) {
-//             if (debug)
-//                     System.out.println("# OSGiBOOT DBG  # " + dateFormat.format(new Date()) + " # " + obj);
                logger.log(Level.TRACE, () -> Objects.toString(obj));
        }
 
-       @Deprecated
        public static void warn(Object obj) {
-//             System.out.println("# OSGiBOOT WARN # " + dateFormat.format(new Date()) + " # " + obj);
                logger.log(Level.WARNING, () -> Objects.toString(obj));
        }
 
-       @Deprecated
        public static void error(Object obj, Throwable e) {
-//             System.err.println("# OSGiBOOT ERR  # " + dateFormat.format(new Date()) + " # " + obj);
-//             if (e != null)
-//                     e.printStackTrace();
                logger.log(Level.ERROR, () -> Objects.toString(obj), e);
        }
 
-       @Deprecated
        public static boolean isDebug() {
-//             return debug;
                return logger.isLoggable(Level.TRACE);
        }
 
index 7eb311fd0d91be0c0fba5918cf8d32c707005fa2..ddea4a5b7a351bb4835e6891a0648eaa6d46377b 100644 (file)
@@ -18,7 +18,14 @@ ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java \
 -Dosgi.configuration.area=/var/lib/argeo.d/%I/state \
 -Dosgi.instance.area=/var/lib/argeo.d/%I/data \
 -Dargeo.node.repo.indexesBase=/var/cache/argeo.d/%I/indexes \
--Dorg.osgi.framework.system.packages.extra=com.sun.net.httpserver,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 \
+-Dorg.osgi.framework.system.packages.extra=\
+com.sun.net.httpserver,\
+com.sun.jndi.ldap,\
+com.sun.jndi.ldap.sasl,\
+com.sun.jndi.dns,\
+com.sun.security.jgss,\
+com.sun.nio.file,\
+com.sun.nio.sctp \
 -Declipse.ignoreApp=true \
 -Dosgi.noShutdown=true \
 -Dorg.eclipse.equinox.http.jetty.autostart=false \