1 package org
.argeo
.api
.init
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
6 import java
.io
.StringReader
;
7 import java
.io
.UncheckedIOException
;
8 import java
.nio
.file
.Files
;
9 import java
.nio
.file
.Path
;
11 import java
.util
.Properties
;
12 import java
.util
.function
.Consumer
;
14 /** Dynamically manages multiple runtimes within a single JVM. */
15 public interface RuntimeManager
{
16 String JVM_ARGS
= "jvm.args";
17 String STATE
= "state";
18 String OSGI_STORAGE_DIRNAME
= "osgi";
20 String SHARED
= "shared";
22 public void startRuntime(String relPath
, Consumer
<Map
<String
, String
>> configCallback
);
24 public void closeRuntime(String relPath
, boolean async
);
26 default void startRuntime(String relPath
, String props
) {
27 startRuntime(relPath
, (config
) -> {
28 loadProperties(config
, props
);
32 static void loadProperties(Map
<String
, String
> config
, Properties properties
) {
33 for (Object key
: properties
.keySet()) {
34 config
.put(key
.toString(), properties
.getProperty(key
.toString()));
38 static void loadProperties(Map
<String
, String
> config
, String props
) {
39 Properties properties
= new Properties();
40 try (Reader reader
= new StringReader(props
)) {
41 properties
.load(reader
);
42 } catch (IOException e
) {
43 throw new IllegalArgumentException("Cannot load properties", e
);
45 loadProperties(config
, properties
);
48 static void loadProperties(Map
<String
, String
> config
, InputStream in
) throws IOException
{
49 Properties properties
= new Properties();
51 loadProperties(config
, properties
);
54 static void loadDefaults(Map
<String
, String
> config
) {
55 try (InputStream in
= RuntimeManager
.class.getResourceAsStream("defaults.ini")) {
56 loadProperties(config
, in
);
57 } catch (IOException e
) {
58 throw new IllegalStateException("Could not load runtime defaults", e
);
63 * Load configs recursively starting with the parent directories, until a
64 * jvm.args file is found.
67 static void loadConfig(Path dir
, Map
<String
, String
> config
) {
69 Path jvmArgsPath
= dir
.resolve(RuntimeManager
.JVM_ARGS
);
70 if (!Files
.exists(jvmArgsPath
)) {
71 // load from parent directory
72 loadConfig(dir
.getParent(), config
);
75 if (Files
.exists(dir
))
76 for (Path p
: Files
.newDirectoryStream(dir
, "*.ini")) {
77 try (InputStream in
= Files
.newInputStream(p
)) {
78 loadConfig(in
, config
);
81 } catch (IOException e
) {
82 throw new UncheckedIOException("Cannot load configuration from " + dir
, e
);
87 * Load config from a {@link Properties} formatted stream. If a property value
88 * starts with a '+' character, it is expected that the last character is a
89 * separator and it will be prepended to the existing value.
92 static void loadConfig(InputStream in
, Map
<String
, String
> config
) throws IOException
{
93 Properties props
= new Properties();
95 for (Object k
: props
.keySet()) {
96 String key
= k
.toString();
97 String value
= props
.getProperty(key
);
98 if (value
.length() > 1 && '+' == value
.charAt(0)) {
99 String currentValue
= config
.get(key
);
100 if (currentValue
== null || "".equals(currentValue
)) {
101 // remove the + and the trailing separator
102 value
= value
.substring(1, value
.length() - 1);
103 config
.put(key
, value
);
105 // remove the + but keep the trailing separator
106 value
= value
.substring(1);
107 config
.put(key
, value
+ currentValue
);
110 config
.put(key
, value
);