import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.lang.System.LoggerFinder;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.concurrent.Flow;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import org.argeo.api.init.InitConstants;
import org.argeo.api.init.RuntimeContext;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
import org.osgi.framework.launch.Framework;
-import org.osgi.framework.launch.FrameworkFactory;
/** An OSGi runtime context. */
public class OsgiRuntimeContext implements RuntimeContext, AutoCloseable {
private final static long STOP_FOR_UPDATE_TIMEOUT = 60 * 1000;
private final static long CLOSE_TIMEOUT = 60 * 1000;
- // private final static String SYMBOLIC_NAME_FELIX_SCR = "org.apache.felix.scr";
-
+ private final ConnectFrameworkFactory frameworkFactory;
private Map<String, String> config;
private Framework framework;
-// private OsgiBoot osgiBoot;
+
+ // Nested runtimes
+// private final BundleContext foreignBundleContext;
+ // private final List<String> foreignCategories;
+
+ private final ForeignModuleConnector moduleConnector;
/**
* Constructor to use when the runtime context will create the OSGi
* {@link Framework}.
*/
- public OsgiRuntimeContext(Map<String, String> config) {
+ public OsgiRuntimeContext(ConnectFrameworkFactory frameworkFactory, Map<String, String> config) {
+ this(frameworkFactory, config, null, null);
+ }
+
+ /**
+ * Constructor to use when the runtime context will create the OSGi
+ * {@link Framework} and will potentially have a parent runtime.
+ */
+ OsgiRuntimeContext(ConnectFrameworkFactory frameworkFactory, Map<String, String> config,
+ BundleContext foreignBundleContext, List<String> foreignCategories) {
+ this.frameworkFactory = frameworkFactory;
this.config = config;
+ if (foreignCategories != null) {
+// String parentCategories = config.get(InitConstants.PROP_ARGEO_OSGI_PARENT_CATEGORIES);
+// if (parentCategories != null) {
+// Objects.requireNonNull(foreignBundleContext, "Foreign bundle context");
+// List<String> foreignCategories = Arrays.asList(parentCategories.trim().split(","));
+// foreignCategories.removeIf((s) -> "".equals(s));
+ this.moduleConnector = new ForeignModuleConnector(foreignBundleContext, foreignCategories);
+ } else {
+ this.moduleConnector = null;
+ }
}
/**
* means.
*/
OsgiRuntimeContext(BundleContext bundleContext) {
+ this.frameworkFactory = null;
+ // TODO try nesting within Eclipse PDE
+ this.moduleConnector = null;
start(bundleContext);
}
throw new IllegalStateException("OSGi framework is already started");
if (framework == null) {
- ServiceLoader<FrameworkFactory> sl = ServiceLoader.load(FrameworkFactory.class);
- Optional<FrameworkFactory> opt = sl.findFirst();
- if (opt.isEmpty())
- throw new IllegalStateException("Cannot find OSGi framework");
- framework = opt.get().newFramework(config);
+// ServiceLoader<FrameworkFactory> sl = ServiceLoader.load(FrameworkFactory.class);
+// Optional<FrameworkFactory> opt = sl.findFirst();
+// if (opt.isEmpty())
+// throw new IllegalStateException("Cannot find OSGi framework");
+// framework = opt.get().newFramework(config);
+ framework = frameworkFactory.newFramework(config, moduleConnector);
}
try {
framework.start();
BundleContext bundleContext = framework.getBundleContext();
+ bundleContext.registerService(ConnectFrameworkFactory.class, frameworkFactory, null);
start(bundleContext);
} catch (BundleException e) {
throw new IllegalStateException("Cannot start OSGi framework", e);
OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
String frameworkUuuid = bundleContext.getProperty(Constants.FRAMEWORK_UUID);
+// osgiBoot.bootstrap();
+
// separate thread in order to improve logging
Thread osgiBootThread = new Thread("OSGi boot framework " + frameworkUuuid) {
@Override
public void run() {
- osgiBoot.bootstrap(config);
+ osgiBoot.bootstrap();
}
};
osgiBootThread.start();
return framework;
}
+ /**
+ * Load {@link ConnectFrameworkFactory} from Java service loader. This will not
+ * work within a pure OSGi runtime, so the reference should be passed to child
+ * runtimes as an OSGi service.
+ */
+ public static ConnectFrameworkFactory loadFrameworkFactory() {
+ ServiceLoader<ConnectFrameworkFactory> sl = ServiceLoader.load(ConnectFrameworkFactory.class);
+ Optional<ConnectFrameworkFactory> opt = sl.findFirst();
+ if (opt.isEmpty())
+ throw new IllegalStateException("Cannot find OSGi framework factory");
+ return opt.get();
+ }
+
+ public static ConnectFrameworkFactory getFrameworkFactory(BundleContext bundleContext) {
+ ServiceReference<ConnectFrameworkFactory> sr = bundleContext.getServiceReference(ConnectFrameworkFactory.class);
+ if (sr == null)
+ return null;
+ return bundleContext.getService(sr);
+ }
}