1 package org
.argeo
.init
.osgi
;
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
;
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
;
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
.ServiceReference
;
21 import org
.osgi
.framework
.connect
.ConnectFrameworkFactory
;
22 import org
.osgi
.framework
.launch
.Framework
;
24 /** An OSGi runtime context. */
25 public class OsgiRuntimeContext
implements RuntimeContext
, AutoCloseable
{
26 private final static Logger logger
= System
.getLogger(OsgiRuntimeContext
.class.getName());
28 private final static long STOP_FOR_UPDATE_TIMEOUT
= 60 * 1000;
29 private final static long CLOSE_TIMEOUT
= 60 * 1000;
31 // private final static String SYMBOLIC_NAME_FELIX_SCR = "org.apache.felix.scr";
33 private ConnectFrameworkFactory frameworkFactory
;
34 private Map
<String
, String
> config
;
35 private Framework framework
;
36 // private OsgiBoot osgiBoot;
39 * Constructor to use when the runtime context will create the OSGi
42 public OsgiRuntimeContext(ConnectFrameworkFactory frameworkFactory
, Map
<String
, String
> config
) {
43 this.frameworkFactory
= frameworkFactory
;
48 * Constructor to use when the OSGi {@link Framework} has been created by other
51 OsgiRuntimeContext(BundleContext bundleContext
) {
57 if (framework
!= null && framework
.getState() >= Framework
.STARTING
)
58 throw new IllegalStateException("OSGi framework is already started");
60 if (framework
== null) {
61 // ServiceLoader<FrameworkFactory> sl = ServiceLoader.load(FrameworkFactory.class);
62 // Optional<FrameworkFactory> opt = sl.findFirst();
64 // throw new IllegalStateException("Cannot find OSGi framework");
65 // framework = opt.get().newFramework(config);
66 framework
= frameworkFactory
.newFramework(config
, null);
71 BundleContext bundleContext
= framework
.getBundleContext();
72 bundleContext
.registerService(ConnectFrameworkFactory
.class, frameworkFactory
, null);
74 } catch (BundleException e
) {
75 throw new IllegalStateException("Cannot start OSGi framework", e
);
79 protected void start(BundleContext bundleContext
) {
81 // SystemRootPreferences systemRootPreferences = ThinPreferencesFactory.getInstance().getSystemRootPreferences();
82 // bundleContext.registerService(AbstractPreferences.class, systemRootPreferences, new Hashtable<>());
84 // Make sure LoggerFinder has been searched for, since it is lazily loaded
85 LoggerFinder loggerFinder
= LoggerFinder
.getLoggerFinder();
87 if (loggerFinder
instanceof Consumer
<?
> && loggerFinder
instanceof Supplier
<?
>) {
88 @SuppressWarnings("unchecked")
89 Consumer
<Map
<String
, Object
>> consumer
= (Consumer
<Map
<String
, Object
>>) loggerFinder
;
90 // ThinLoggerFinder.getConfigurationConsumer()
91 // ThinLoggerFinder.getLogEntryPublisher()
93 @SuppressWarnings("unchecked")
94 Supplier
<Flow
.Publisher
<Map
<String
, Serializable
>>> supplier
= (Supplier
<Flow
.Publisher
<Map
<String
, Serializable
>>>) loggerFinder
;
96 bundleContext
.registerService(Consumer
.class, consumer
,
97 new Hashtable
<>(Collections
.singletonMap(Constants
.SERVICE_PID
, "argeo.logging.configuration")));
98 bundleContext
.registerService(Flow
.Publisher
.class, supplier
.get(),
99 new Hashtable
<>(Collections
.singletonMap(Constants
.SERVICE_PID
, "argeo.logging.publisher")));
101 OsgiBoot osgiBoot
= new OsgiBoot(bundleContext
);
102 String frameworkUuuid
= bundleContext
.getProperty(Constants
.FRAMEWORK_UUID
);
104 // separate thread in order to improve logging
105 Thread osgiBootThread
= new Thread("OSGi boot framework " + frameworkUuuid
) {
108 osgiBoot
.bootstrap();
111 osgiBootThread
.start();
112 // TODO return a completable stage so that inits can run in parallel
114 // osgiBootThread.join(60 * 1000);
115 // } catch (InterruptedException e) {
120 public void update() {
123 waitForStop(STOP_FOR_UPDATE_TIMEOUT
);
124 } catch (InterruptedException e
) {
125 logger
.log(Level
.TRACE
, "Wait for stop interrupted", e
);
129 // TODO Optimise with OSGi mechanisms (e.g. framework.update())
130 // if (osgiBoot != null) {
131 // Objects.requireNonNull(osgiBoot);
132 // osgiBoot.update();
136 protected void stop() {
137 if (framework
== null)
139 stop(framework
.getBundleContext());
142 } catch (BundleException e
) {
143 throw new IllegalStateException("Cannot stop OSGi framework", e
);
147 protected void stop(BundleContext bundleContext
) {
148 // if (loggingConfigurationSr != null)
150 // loggingConfigurationSr.unregister();
151 // } catch (Exception e) {
154 // if (logEntryPublisherSr != null)
156 // logEntryPublisherSr.unregister();
157 // } catch (Exception e) {
163 public void waitForStop(long timeout
) throws InterruptedException
{
164 if (framework
== null)
167 framework
.waitForStop(timeout
);
170 public void close() throws Exception
{
171 if (framework
== null)
173 // TODO make shutdown of dynamic service more robust
174 // for (Bundle scrBundle : framework.getBundleContext().getBundles()) {
175 // if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) {
176 // if (scrBundle.getState() > Bundle.RESOLVED) {
178 // while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
179 // Thread.sleep(100);
181 // Thread.sleep(500);
187 waitForStop(CLOSE_TIMEOUT
);
193 public Framework
getFramework() {
198 * Load {@link ConnectFrameworkFactory} from Java service loader. This will not
199 * work within a pure OSGi runtime, so the reference should be passed to child
200 * runtimes as an OSGi service.
202 public static ConnectFrameworkFactory
loadFrameworkFactory() {
203 ServiceLoader
<ConnectFrameworkFactory
> sl
= ServiceLoader
.load(ConnectFrameworkFactory
.class);
204 Optional
<ConnectFrameworkFactory
> opt
= sl
.findFirst();
206 throw new IllegalStateException("Cannot find OSGi framework factory");
210 public static ConnectFrameworkFactory
getFrameworkFactory(BundleContext bundleContext
) {
211 ServiceReference
<ConnectFrameworkFactory
> sr
= bundleContext
.getServiceReference(ConnectFrameworkFactory
.class);
214 return bundleContext
.getService(sr
);