1 package org
.argeo
.init
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.lang
.System
.Logger
;
6 import java
.lang
.System
.Logger
.Level
;
7 import java
.nio
.file
.Files
;
8 import java
.nio
.file
.Path
;
9 import java
.nio
.file
.Paths
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Collections
;
12 import java
.util
.HashMap
;
13 import java
.util
.List
;
15 import java
.util
.Objects
;
16 import java
.util
.Properties
;
17 import java
.util
.TreeMap
;
19 import org
.argeo
.init
.logging
.ThinLoggerFinder
;
20 import org
.argeo
.init
.osgi
.OsgiBoot
;
21 import org
.argeo
.init
.osgi
.OsgiRuntimeContext
;
23 /** Configure and launch an Argeo service. */
24 public class Service
{
25 private final static Logger logger
= System
.getLogger(Service
.class.getName());
27 final static String FILE_SYSTEM_PROPERTIES
= "system.properties";
29 public final static String PROP_ARGEO_INIT_MAIN
= "argeo.init.main";
31 private static RuntimeContext runtimeContext
= null;
33 private static List
<Runnable
> postStart
= Collections
.synchronizedList(new ArrayList
<>());
35 protected Service(String
[] args
) {
38 public static void main(String
[] args
) {
39 final long pid
= ProcessHandle
.current().pid();
40 logger
.log(Logger
.Level
.DEBUG
, () -> "Argeo Init starting with PID " + pid
);
43 Runtime
.getRuntime().addShutdownHook(new Thread(() -> {
45 if (Service
.runtimeContext
!= null) {
46 // System.out.println("Argeo Init stopping with PID " + pid);
47 Service
.runtimeContext
.close();
48 Service
.runtimeContext
.waitForStop(0);
50 } catch (Exception e
) {
52 Runtime
.getRuntime().halt(1);
54 }, "Runtime shutdown"));
56 // TODO use args as well
57 String dataArea
= System
.getProperty(OsgiBoot
.PROP_OSGI_INSTANCE_AREA
);
58 String stateArea
= System
.getProperty(OsgiBoot
.PROP_OSGI_CONFIGURATION_AREA
);
59 String configArea
= System
.getProperty(OsgiBoot
.PROP_OSGI_SHARED_CONFIGURATION_AREA
);
61 if (configArea
!= null) {
62 Path configAreaPath
= Paths
.get(configArea
);
63 Path additionalSystemPropertiesPath
= configAreaPath
.resolve(FILE_SYSTEM_PROPERTIES
);
64 if (Files
.exists(additionalSystemPropertiesPath
)) {
65 Properties properties
= new Properties();
66 try (InputStream in
= Files
.newInputStream(additionalSystemPropertiesPath
)) {
68 } catch (IOException e
) {
69 logger
.log(Logger
.Level
.ERROR
,
70 "Cannot load additional system properties " + additionalSystemPropertiesPath
, e
);
73 for (Object key
: properties
.keySet()) {
74 String currentValue
= System
.getProperty(key
.toString());
75 String value
= properties
.getProperty(key
.toString());
76 if (currentValue
!= null) {
77 if (!Objects
.equals(value
, currentValue
))
78 logger
.log(Logger
.Level
.WARNING
, "System property " + key
+ " already set with value "
79 + currentValue
+ " instead of " + value
+ ". Ignoring new value.");
81 System
.setProperty(key
.toString(), value
);
82 logger
.log(Logger
.Level
.TRACE
, () -> "Added " + key
+ "=" + value
83 + " to system properties, from " + additionalSystemPropertiesPath
.getFileName());
86 ThinLoggerFinder
.reloadConfiguration();
90 Map
<String
, String
> config
= new HashMap
<>();
91 config
.put(PROP_ARGEO_INIT_MAIN
, "true");
93 // add OSGi system properties to the configuration
94 sysprops
: for (Object key
: new TreeMap
<>(System
.getProperties()).keySet()) {
95 String keyStr
= key
.toString();
97 case OsgiBoot
.PROP_OSGI_CONFIGURATION_AREA
:
98 case OsgiBoot
.PROP_OSGI_SHARED_CONFIGURATION_AREA
:
99 case OsgiBoot
.PROP_OSGI_INSTANCE_AREA
:
100 // we should already have dealt with those
105 if (keyStr
.startsWith("osgi.") || keyStr
.startsWith("org.osgi.") || keyStr
.startsWith("eclipse.")
106 || keyStr
.startsWith("org.eclipse.equinox.") || keyStr
.startsWith("felix.")) {
107 String value
= System
.getProperty(keyStr
);
108 config
.put(keyStr
, value
);
109 logger
.log(Logger
.Level
.TRACE
,
110 () -> "Added " + key
+ "=" + value
+ " to configuration, from system properties");
116 if (stateArea
!= null)
117 config
.put(OsgiBoot
.PROP_OSGI_CONFIGURATION_AREA
, stateArea
);
118 if (configArea
!= null)
119 config
.put(OsgiBoot
.PROP_OSGI_SHARED_CONFIGURATION_AREA
, configArea
);
120 if (dataArea
!= null)
121 config
.put(OsgiBoot
.PROP_OSGI_INSTANCE_AREA
, dataArea
);
122 // config.put(OsgiBoot.PROP_OSGI_USE_SYSTEM_PROPERTIES, "true");
124 OsgiRuntimeContext osgiRuntimeContext
= new OsgiRuntimeContext(config
);
125 osgiRuntimeContext
.run();
126 Service
.runtimeContext
= osgiRuntimeContext
;
127 for (Runnable run
: postStart
) {
130 } catch (Exception e
) {
131 logger
.log(Level
.ERROR
, "Cannot run post start callback " + run
, e
);
134 Service
.runtimeContext
.waitForStop(0);
135 } catch (NoClassDefFoundError noClassDefFoundE
) {
136 StaticRuntimeContext staticRuntimeContext
= new StaticRuntimeContext((Map
<String
, String
>) config
);
137 staticRuntimeContext
.run();
138 Service
.runtimeContext
= staticRuntimeContext
;
139 for (Runnable run
: postStart
) {
142 } catch (Exception e
) {
143 logger
.log(Level
.ERROR
, "Cannot run post start callback " + run
, e
);
146 Service
.runtimeContext
.waitForStop(0);
148 } catch (Exception e
) {
152 logger
.log(Logger
.Level
.DEBUG
, "Argeo Init stopped with PID " + pid
);
155 /** The root runtime context in this JVM. */
156 public static RuntimeContext
getRuntimeContext() {
157 return runtimeContext
;
160 /** Add a post-start call back to be run after the runtime has been started. */
161 public static void addPostStart(Runnable runnable
) {
162 postStart
.add(runnable
);