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
.Bundle
;
18 import org
.osgi
.framework
.BundleContext
;
19 import org
.osgi
.framework
.BundleException
;
20 import org
.osgi
.framework
.Constants
;
21 import org
.osgi
.framework
.launch
.Framework
;
22 import org
.osgi
.framework
.launch
.FrameworkFactory
;
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 Map
<String
, String
> config
;
34 private Framework framework
;
35 // private OsgiBoot osgiBoot;
38 * Constructor to use when the runtime context will create the OSGi
41 public OsgiRuntimeContext(Map
<String
, String
> config
) {
46 * Constructor to use when the OSGi {@link Framework} has been created by other
49 OsgiRuntimeContext(BundleContext bundleContext
) {
55 if (framework
!= null && framework
.getState() >= Framework
.STARTING
)
56 throw new IllegalStateException("OSGi framework is already started");
58 if (framework
== null) {
59 ServiceLoader
<FrameworkFactory
> sl
= ServiceLoader
.load(FrameworkFactory
.class);
60 Optional
<FrameworkFactory
> opt
= sl
.findFirst();
62 throw new IllegalStateException("Cannot find OSGi framework");
63 framework
= opt
.get().newFramework(config
);
68 BundleContext bundleContext
= framework
.getBundleContext();
70 } catch (BundleException e
) {
71 throw new IllegalStateException("Cannot start OSGi framework", e
);
75 protected void start(BundleContext bundleContext
) {
77 // SystemRootPreferences systemRootPreferences = ThinPreferencesFactory.getInstance().getSystemRootPreferences();
78 // bundleContext.registerService(AbstractPreferences.class, systemRootPreferences, new Hashtable<>());
80 // Make sure LoggerFinder has been searched for, since it is lazily loaded
81 LoggerFinder loggerFinder
= LoggerFinder
.getLoggerFinder();
83 if (loggerFinder
instanceof Consumer
<?
> && loggerFinder
instanceof Supplier
<?
>) {
84 @SuppressWarnings("unchecked")
85 Consumer
<Map
<String
, Object
>> consumer
= (Consumer
<Map
<String
, Object
>>) loggerFinder
;
86 // ThinLoggerFinder.getConfigurationConsumer()
87 // ThinLoggerFinder.getLogEntryPublisher()
89 @SuppressWarnings("unchecked")
90 Supplier
<Flow
.Publisher
<Map
<String
, Serializable
>>> supplier
= (Supplier
<Flow
.Publisher
<Map
<String
, Serializable
>>>) loggerFinder
;
92 bundleContext
.registerService(Consumer
.class, consumer
,
93 new Hashtable
<>(Collections
.singletonMap(Constants
.SERVICE_PID
, "argeo.logging.configuration")));
94 bundleContext
.registerService(Flow
.Publisher
.class, supplier
.get(),
95 new Hashtable
<>(Collections
.singletonMap(Constants
.SERVICE_PID
, "argeo.logging.publisher")));
97 OsgiBoot osgiBoot
= new OsgiBoot(bundleContext
);
98 String frameworkUuuid
= bundleContext
.getProperty(Constants
.FRAMEWORK_UUID
);
100 // separate thread in order to improve logging
101 Thread osgiBootThread
= new Thread("OSGi boot framework " + frameworkUuuid
) {
104 osgiBoot
.bootstrap(config
);
107 osgiBootThread
.start();
108 // TODO return a completable stage so that inits can run in parallel
110 // osgiBootThread.join(60 * 1000);
111 // } catch (InterruptedException e) {
116 public void update() {
119 waitForStop(STOP_FOR_UPDATE_TIMEOUT
);
120 } catch (InterruptedException e
) {
121 logger
.log(Level
.TRACE
, "Wait for stop interrupted", e
);
125 // TODO Optimise with OSGi mechanisms (e.g. framework.update())
126 // if (osgiBoot != null) {
127 // Objects.requireNonNull(osgiBoot);
128 // osgiBoot.update();
132 protected void stop() {
133 if (framework
== null)
135 stop(framework
.getBundleContext());
138 } catch (BundleException e
) {
139 throw new IllegalStateException("Cannot stop OSGi framework", e
);
143 protected void stop(BundleContext bundleContext
) {
144 // if (loggingConfigurationSr != null)
146 // loggingConfigurationSr.unregister();
147 // } catch (Exception e) {
150 // if (logEntryPublisherSr != null)
152 // logEntryPublisherSr.unregister();
153 // } catch (Exception e) {
159 public void waitForStop(long timeout
) throws InterruptedException
{
160 if (framework
== null)
163 framework
.waitForStop(timeout
);
166 public void close() throws Exception
{
167 if (framework
== null)
169 // TODO make shutdown of dynamic service more robust
170 // for (Bundle scrBundle : framework.getBundleContext().getBundles()) {
171 // if (scrBundle.getSymbolicName().equals(SYMBOLIC_NAME_FELIX_SCR)) {
172 // if (scrBundle.getState() > Bundle.RESOLVED) {
174 // while (!(scrBundle.getState() <= Bundle.RESOLVED)) {
175 // Thread.sleep(100);
177 // Thread.sleep(500);
183 waitForStop(CLOSE_TIMEOUT
);
189 public Framework
getFramework() {