]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeManager.java
Improve init launch
[lgpl/argeo-commons.git] / org.argeo.init / src / org / argeo / init / osgi / OsgiRuntimeManager.java
1 package org.argeo.init.osgi;
2
3 import java.lang.System.Logger;
4 import java.lang.System.Logger.Level;
5 import java.net.URI;
6 import java.nio.file.Path;
7 import java.nio.file.Paths;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Map;
11 import java.util.TreeMap;
12 import java.util.function.Consumer;
13
14 import org.argeo.api.init.InitConstants;
15 import org.argeo.api.init.RuntimeContext;
16 import org.argeo.api.init.RuntimeManager;
17 import org.argeo.internal.init.InternalState;
18 import org.osgi.framework.BundleContext;
19 import org.osgi.framework.FrameworkEvent;
20 import org.osgi.framework.connect.ConnectFrameworkFactory;
21 import org.osgi.framework.launch.Framework;
22
23 /**
24 * Dynamically configures and launches multiple runtimes.
25 */
26 class OsgiRuntimeManager implements RuntimeManager {
27 private final static Logger logger = System.getLogger(OsgiRuntimeManager.class.getName());
28
29 private final static long RUNTIME_SHUTDOWN_TIMEOUT = 60 * 1000;
30
31 private Path baseConfigArea;
32 private Path baseWritableArea;
33 private Map<String, String> configuration = new HashMap<>();
34
35 private Map<String, OsgiRuntimeContext> runtimeContexts = new TreeMap<>();
36
37 private ConnectFrameworkFactory frameworkFactory;
38
39 OsgiRuntimeManager(BundleContext bundleContext) {
40 frameworkFactory = OsgiRuntimeContext.getFrameworkFactory(bundleContext);
41 this.baseConfigArea = Paths
42 .get(URI.create(bundleContext.getProperty(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA)))
43 .getParent();
44 this.baseWritableArea = Paths
45 .get(URI.create(bundleContext.getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA))).getParent()
46 .getParent();
47
48 logger.log(Level.TRACE, () -> "Runtime manager configuration: " + configuration);
49
50 // System.out.println("java.library.path=" + System.getProperty("java.library.path"));
51 }
52
53 protected void shutdown() {
54 // shutdowm runtimes
55 Map<String, RuntimeContext> shutdowning = new HashMap<>(runtimeContexts);
56 for (String id : new HashSet<>(runtimeContexts.keySet())) {
57 logger.log(Logger.Level.DEBUG, "Shutting down runtime " + id + " ...");
58 closeRuntime(id, true);
59 }
60 for (String id : shutdowning.keySet())
61 try {
62 RuntimeContext runtimeContext = shutdowning.get(id);
63 runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
64 } catch (InterruptedException e) {
65 // silent
66 } catch (Exception e) {
67 logger.log(Logger.Level.DEBUG, "Cannot wait for " + id + " to shutdown", e);
68 }
69 // shutdown manager runtime
70 try {
71 InternalState.getMainRuntimeContext().close();
72 InternalState.getMainRuntimeContext().waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
73 // logger.log(Logger.Level.INFO, "Argeo Init stopped with PID " + ProcessHandle.current().pid());
74 System.out.flush();
75 } catch (Exception e) {
76 e.printStackTrace();
77 Runtime.getRuntime().halt(1);
78 }
79 }
80
81 OsgiRuntimeContext loadRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
82 closeRuntime(relPath, false);
83 Path writableArea = baseWritableArea.resolve(relPath);
84 Path configArea = baseConfigArea.resolve(relPath);
85 Map<String, String> config = new HashMap<>();
86 RuntimeManager.loadConfig(configArea, config);
87 config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, writableArea.resolve(STATE).toUri().toString());
88
89 if (configCallback != null)
90 configCallback.accept(config);
91
92 // use config area if instance area is not set
93 if (!config.containsKey(InitConstants.PROP_OSGI_INSTANCE_AREA))
94 config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, writableArea.resolve(DATA).toUri().toString());
95
96 // create framework
97 // Framework framework = frameworkFactory.newFramework(config, null);
98 // try {
99 // framework.start();
100 // } catch (BundleException e) {
101 // throw new IllegalStateException("Cannot initialise framework", e);
102 // }
103 OsgiRuntimeContext runtimeContext = new OsgiRuntimeContext(frameworkFactory, config);
104 runtimeContexts.put(relPath, runtimeContext);
105 return runtimeContext;
106 }
107
108 public void startRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
109 OsgiRuntimeContext runtimeContext = loadRuntime(relPath, configCallback);
110 runtimeContext.run();
111 Framework framework = runtimeContext.getFramework();
112 if (framework != null) {// in case the framework has closed very quickly after run
113 framework.getBundleContext().addFrameworkListener((e) -> {
114 if (e.getType() >= FrameworkEvent.STOPPED) {
115 logger.log(Level.DEBUG, "Externally stopped runtime " + relPath + ". Unregistering...", e);
116 runtimeContexts.remove(relPath);
117 }
118 });
119 } else {
120 closeRuntime(relPath, false);
121 }
122 }
123
124 public void closeRuntime(String relPath, boolean async) {
125 if (!runtimeContexts.containsKey(relPath))
126 return;
127 RuntimeContext runtimeContext = runtimeContexts.get(relPath);
128 try {
129 runtimeContext.close();
130 if (!async) {
131 runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
132 System.gc();
133 }
134 } catch (Exception e) {
135 logger.log(Level.ERROR, "Cannot close runtime context " + relPath, e);
136 } finally {
137 runtimeContexts.remove(relPath);
138 }
139
140 }
141 }