1 package org
.argeo
.init
.osgi
;
3 import java
.lang
.System
.Logger
;
4 import java
.lang
.System
.Logger
.Level
;
6 import java
.nio
.file
.Path
;
7 import java
.nio
.file
.Paths
;
8 import java
.util
.HashMap
;
9 import java
.util
.HashSet
;
11 import java
.util
.TreeMap
;
12 import java
.util
.function
.Consumer
;
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
;
24 * Dynamically configures and launches multiple runtimes.
26 class OsgiRuntimeManager
implements RuntimeManager
{
27 private final static Logger logger
= System
.getLogger(OsgiRuntimeManager
.class.getName());
29 private final static long RUNTIME_SHUTDOWN_TIMEOUT
= 60 * 1000;
31 private Path baseConfigArea
;
32 private Path baseWritableArea
;
33 private Map
<String
, String
> configuration
= new HashMap
<>();
35 private Map
<String
, OsgiRuntimeContext
> runtimeContexts
= new TreeMap
<>();
37 private ConnectFrameworkFactory frameworkFactory
;
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
)))
44 this.baseWritableArea
= Paths
45 .get(URI
.create(bundleContext
.getProperty(InitConstants
.PROP_OSGI_CONFIGURATION_AREA
))).getParent()
48 logger
.log(Level
.TRACE
, () -> "Runtime manager configuration: " + configuration
);
50 // System.out.println("java.library.path=" + System.getProperty("java.library.path"));
53 protected void shutdown() {
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);
60 for (String id
: shutdowning
.keySet())
62 RuntimeContext runtimeContext
= shutdowning
.get(id
);
63 runtimeContext
.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT
);
64 } catch (InterruptedException e
) {
66 } catch (Exception e
) {
67 logger
.log(Logger
.Level
.DEBUG
, "Cannot wait for " + id
+ " to shutdown", e
);
69 // shutdown manager runtime
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());
75 } catch (Exception e
) {
77 Runtime
.getRuntime().halt(1);
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());
89 if (configCallback
!= null)
90 configCallback
.accept(config
);
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());
97 // Framework framework = frameworkFactory.newFramework(config, null);
100 // } catch (BundleException e) {
101 // throw new IllegalStateException("Cannot initialise framework", e);
103 OsgiRuntimeContext runtimeContext
= new OsgiRuntimeContext(frameworkFactory
, config
);
104 runtimeContexts
.put(relPath
, runtimeContext
);
105 return runtimeContext
;
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
);
120 closeRuntime(relPath
, false);
124 public void closeRuntime(String relPath
, boolean async
) {
125 if (!runtimeContexts
.containsKey(relPath
))
127 RuntimeContext runtimeContext
= runtimeContexts
.get(relPath
);
129 runtimeContext
.close();
131 runtimeContext
.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT
);
134 } catch (Exception e
) {
135 logger
.log(Level
.ERROR
, "Cannot close runtime context " + relPath
, e
);
137 runtimeContexts
.remove(relPath
);