]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.init/src/org/argeo/init/osgi/OsgiRuntimeContext.java
Simplify multi-runtime
[lgpl/argeo-commons.git] / org.argeo.init / src / org / argeo / init / osgi / OsgiRuntimeContext.java
1 package org.argeo.init.osgi;
2
3 import java.io.Serializable;
4 import java.lang.System.Logger;
5 import java.lang.System.Logger.Level;
6 import java.lang.System.LoggerFinder;
7 import java.util.Collections;
8 import java.util.Hashtable;
9 import java.util.Map;
10 import java.util.Optional;
11 import java.util.ServiceLoader;
12 import java.util.concurrent.Flow;
13 import java.util.function.Consumer;
14 import java.util.function.Supplier;
15
16 import org.argeo.api.init.RuntimeContext;
17 import org.osgi.framework.BundleContext;
18 import org.osgi.framework.BundleException;
19 import org.osgi.framework.Constants;
20 import org.osgi.framework.launch.Framework;
21 import org.osgi.framework.launch.FrameworkFactory;
22
23 /** An OSGi runtime context. */
24 public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable {
25 private final static Logger logger = System.getLogger(OsgiRuntimeContext.class.getName());
26
27 private final static long STOP_FOR_UPDATE_TIMEOUT = 60 * 1000;
28 private final static long CLOSE_TIMEOUT = 60 * 1000;
29
30 // private final static String SYMBOLIC_NAME_FELIX_SCR = "org.apache.felix.scr";
31
32 private Map<String, String> config;
33 private Framework framework;
34 // private OsgiBoot osgiBoot;
35
36 /**
37 * Constructor to use when the runtime context will create the OSGi
38 * {@link Framework}.
39 */
40 public OsgiRuntimeContext(Map<String, String> config) {
41 this.config = config;
42 }
43
44 /**
45 * Constructor to use when the OSGi {@link Framework} has been created by other
46 * means.
47 */
48 OsgiRuntimeContext(BundleContext bundleContext) {
49 start(bundleContext);
50 }
51
52 @Override
53 public void run() {
54 if (framework != null && framework.getState() >= Framework.STARTING)
55 throw new IllegalStateException("OSGi framework is already started");
56
57 if (framework == null) {
58 ServiceLoader<FrameworkFactory> sl = ServiceLoader.load(FrameworkFactory.class);
59 Optional<FrameworkFactory> opt = sl.findFirst();
60 if (opt.isEmpty())
61 throw new IllegalStateException("Cannot find OSGi framework");
62 framework = opt.get().newFramework(config);
63 }
64
65 try {
66 framework.start();
67 BundleContext bundleContext = framework.getBundleContext();
68 start(bundleContext);
69 } catch (BundleException e) {
70 throw new IllegalStateException("Cannot start OSGi framework", e);
71 }
72 }
73
74 protected void start(BundleContext bundleContext) {
75 // preferences
76 // SystemRootPreferences systemRootPreferences = ThinPreferencesFactory.getInstance().getSystemRootPreferences();
77 // bundleContext.registerService(AbstractPreferences.class, systemRootPreferences, new Hashtable<>());
78
79 // Make sure LoggerFinder has been searched for, since it is lazily loaded
80 LoggerFinder loggerFinder = LoggerFinder.getLoggerFinder();
81
82 if (loggerFinder instanceof Consumer<?> && loggerFinder instanceof Supplier<?>) {
83 @SuppressWarnings("unchecked")
84 Consumer<Map<String, Object>> consumer = (Consumer<Map<String, Object>>) loggerFinder;
85 // ThinLoggerFinder.getConfigurationConsumer()
86 // ThinLoggerFinder.getLogEntryPublisher()
87
88 @SuppressWarnings("unchecked")
89 Supplier<Flow.Publisher<Map<String, Serializable>>> supplier = (Supplier<Flow.Publisher<Map<String, Serializable>>>) loggerFinder;
90 // logging
91 bundleContext.registerService(Consumer.class, consumer,
92 new Hashtable<>(Collections.singletonMap(Constants.SERVICE_PID, "argeo.logging.configuration")));
93 bundleContext.registerService(Flow.Publisher.class, supplier.get(),
94 new Hashtable<>(Collections.singletonMap(Constants.SERVICE_PID, "argeo.logging.publisher")));
95 }
96 OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
97 String frameworkUuuid = bundleContext.getProperty(Constants.FRAMEWORK_UUID);
98
99 // separate thread in order to improve logging
100 Thread osgiBootThread = new Thread("OSGi boot framework " + frameworkUuuid) {
101 @Override
102 public void run() {
103 osgiBoot.bootstrap();
104 }
105 };
106 osgiBootThread.start();
107 // TODO return a completable stage so that inits can run in parallel
108 // try {
109 // osgiBootThread.join(60 * 1000);
110 // } catch (InterruptedException e) {
111 // // silent
112 // }
113 }
114
115 public void update() {
116 stop();
117 try {
118 waitForStop(STOP_FOR_UPDATE_TIMEOUT);
119 } catch (InterruptedException e) {
120 logger.log(Level.TRACE, "Wait for stop interrupted", e);
121 }
122 run();
123
124 // TODO Optimise with OSGi mechanisms (e.g. framework.update())
125 // if (osgiBoot != null) {
126 // Objects.requireNonNull(osgiBoot);
127 // osgiBoot.update();
128 // }
129 }
130
131 protected void stop() {
132 if (framework == null)
133 return;
134 stop(framework.getBundleContext());
135 try {
136 framework.stop();
137 } catch (BundleException e) {
138 throw new IllegalStateException("Cannot stop OSGi framework", e);
139 }
140 }
141
142 protected void stop(BundleContext bundleContext) {
143 // if (loggingConfigurationSr != null)
144 // try {
145 // loggingConfigurationSr.unregister();
146 // } catch (Exception e) {
147 // // silent
148 // }
149 // if (logEntryPublisherSr != null)
150 // try {
151 // logEntryPublisherSr.unregister();
152 // } catch (Exception e) {
153 // // silent
154 // }
155 }
156
157 @Override
158 public void waitForStop(long timeout) throws InterruptedException {
159 if (framework == null)
160 return;
161
162 framework.waitForStop(timeout);
163 }
164
165 public void close() throws Exception {
166 if (framework == null)
167 return;
168 // TODO make shutdown of dynamic service more robust
169 // for (Bundle scrBundle : framework.getBundleContext().getBundles()) {
170 // if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) {
171 // if (scrBundle.getState() > Bundle.RESOLVED) {
172 // scrBundle.stop();
173 // while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
174 // Thread.sleep(100);
175 // }
176 // Thread.sleep(500);
177 // }
178 // }
179 // }
180
181 stop();
182 waitForStop(CLOSE_TIMEOUT);
183 framework = null;
184 // osgiBoot = null;
185 config.clear();
186 }
187
188 public Framework getFramework() {
189 return framework;
190 }
191
192 }