package org.argeo.cms.acr;
-import static java.lang.System.Logger.Level.ERROR;
-
import java.net.MalformedURLException;
-import java.net.URI;
import java.net.URL;
import java.util.Objects;
Objects.requireNonNull(namespace);
this.namespace = namespace;
if (resourceFileName != null) {
- // resource = getClass().getResource(RESOURCE_BASE + resourceFileName);
- try {
- // FIXME workaround when in nested OSGi frameworks
- resource = URI.create("platform:/plugin/org.argeo.cms" + RESOURCE_BASE + resourceFileName).toURL();
- } catch (MalformedURLException e) {
- resource = null;
- System.getLogger(CmsContentNamespace.class.getName()).log(ERROR,
- "Cannot load " + resourceFileName + ": " + e.getMessage());
- // throw new IllegalArgumentException("Cannot convert " + resourceFileName + "
- // to URL");
- }
+ resource = getClass().getResource(RESOURCE_BASE + resourceFileName);
+// try {
+// // FIXME workaround when in nested OSGi frameworks
+// resource = URI.create("platform:/plugin/org.argeo.cms" + RESOURCE_BASE + resourceFileName).toURL();
+// } catch (MalformedURLException e) {
+// resource = null;
+// System.getLogger(CmsContentNamespace.class.getName()).log(ERROR,
+// "Cannot load " + resourceFileName + ": " + e.getMessage());
+// // throw new IllegalArgumentException("Cannot convert " + resourceFileName + "
+// // to URL");
+// }
// Objects.requireNonNull(resource);
}
if (publicUrl != null)
Main-Class: org.argeo.init.Service
Class-Path: org.eclipse.osgi.jar
-Bundle-Activator: org.argeo.init.osgi.Activator
+Bundle-Activator: org.argeo.init.osgi.InitActivator
Import-Package: \
org.osgi.*;version=0.0.0,\
String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources";
String PROP_ARGEO_OSGI_START = "argeo.osgi.start";
+
+ String PROP_OSGI_USE_SYSTEM_PROPERTIES = "osgi.framework.useSystemProperties";
+
String PROP_OSGI_INSTANCE_AREA = "osgi.instance.area";
String PROP_OSGI_CONFIGURATION_AREA = "osgi.configuration.area";
String PROP_OSGI_SHARED_CONFIGURATION_AREA = "osgi.sharedConfiguration.area";
+ String PROP_OSGI_SHARED_CONFIGURATION_AREA_RO = "osgi.sharedConfiguration.area.readOnly";
String PROP_ARGEO_OSGI_MAX_START_LEVEL = "argeo.osgi.maxStartLevel";
- /** UUID of the parent framework. Marks a nested runtime. */
- String PROP_ARGEO_OSGI_PARENT_UUID = "argeo.osgi.parent.uuid";
-
- // OSGi standard properties
String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL = "osgi.bundles.defaultStartLevel";
String PROP_OSGI_STARTLEVEL = "osgi.startLevel";
- String PROP_OSGI_USE_SYSTEM_PROPERTIES = "osgi.framework.useSystemProperties";
+
+ // FOREIGN RUNTIME PROPERTIES
+ /**
+ * UUID of the parent framework. It is set by the parent runtime and marks a
+ * nested runtime.
+ */
+ String PROP_ARGEO_OSGI_PARENT_UUID = "argeo.osgi.parent.uuid";
+ /**
+ * The A2 categories to load from the parent. If not specified, nested runtimes
+ * won't be used.
+ */
+ @Deprecated
+ String PROP_ARGEO_OSGI_PARENT_CATEGORIES = "argeo.osgi.parent.categories";
+ String PROP_ARGEO_OSGI_EXPORT_CATEGORIES = "argeo.osgi.export.categories";
+ String PROP_ARGEO_OSGI_EXPORT_ENABLED = "argeo.osgi.export.enabled";
// Symbolic names
String SYMBOLIC_NAME_INIT = "org.argeo.init";
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
String JVM_ARGS = "jvm.args";
String STATE = "state";
String DATA = "data";
+ String SHARED = "shared";
public void startRuntime(String relPath, Consumer<Map<String, String>> configCallback);
public void closeRuntime(String relPath, boolean async);
+ default void startRuntime(String relPath, String props) {
+ startRuntime(relPath, (config) -> {
+ loadProperties(config, props);
+ });
+ }
+
+ static void loadProperties(Map<String, String> config, Properties properties) {
+ for (Object key : properties.keySet()) {
+ config.put(key.toString(), properties.getProperty(key.toString()));
+ }
+ }
+
+ static void loadProperties(Map<String, String> config, String props) {
+ Properties properties = new Properties();
+ try (Reader reader = new StringReader(props)) {
+ properties.load(reader);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Cannot load properties", e);
+ }
+ loadProperties(config, properties);
+ }
+
+ static void loadProperties(Map<String, String> config, InputStream in) throws IOException {
+ Properties properties = new Properties();
+ properties.load(in);
+ loadProperties(config, properties);
+ }
+
+ static void loadDefaults(Map<String, String> config) {
+ try (InputStream in = RuntimeManager.class.getResourceAsStream("defaults.ini")) {
+ loadProperties(config, in);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not load runtime defaults", e);
+ }
+ }
+
/**
* Load configs recursively starting with the parent directories, until a
* jvm.args file is found.
*/
+ @Deprecated
static void loadConfig(Path dir, Map<String, String> config) {
try {
Path jvmArgsPath = dir.resolve(RuntimeManager.JVM_ARGS);
* starts with a '+' character, itis expected that the last character is a
* separator and it will be prepended to the existing value.
*/
+ @Deprecated
static void loadConfig(InputStream in, Map<String, String> config) throws IOException {
Properties props = new Properties();
props.load(in);
--- /dev/null
+# Disable Equinox Jetty autostart
+org.eclipse.equinox.http.jetty.autostart=false
+
+# System packages
+org.osgi.framework.system.packages.extra=\
+sun.misc,\
+sun.security.util,\
+sun.security.internal.spec,\
+sun.security.provider,\
+com.sun.net.httpserver,\
+com.sun.jndi.ldap,\
+com.sun.jndi.ldap.sasl,\
+com.sun.jndi.dns,\
+com.sun.security.jgss,\
+com.sun.nio.file,\
+com.sun.nio.sctp
package org.argeo.init;
-import static org.argeo.api.init.InitConstants.SYMBOLIC_NAME_INIT;
-
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
import java.util.Map;
-import java.util.TreeMap;
-import java.util.function.Consumer;
import org.argeo.api.init.InitConstants;
-import org.argeo.api.init.RuntimeContext;
import org.argeo.api.init.RuntimeManager;
import org.argeo.init.logging.ThinLoggerFinder;
-import org.argeo.init.osgi.OsgiBoot;
import org.argeo.init.osgi.OsgiRuntimeContext;
import org.argeo.internal.init.InternalState;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkEvent;
-import org.osgi.framework.launch.Framework;
/**
* Dynamically configures and launches multiple runtimes, coordinated by a main
* one.
*/
-public class RuntimeManagerMain implements RuntimeManager {
+public class RuntimeManagerMain {
private final static Logger logger = System.getLogger(RuntimeManagerMain.class.getName());
private final static String ENV_STATE_DIRECTORY = "STATE_DIRECTORY";
-// private final static String ENV_CONFIGURATION_DIRECTORY = "CONFIGURATION_DIRECTORY";
+ private final static String ENV_CONFIGURATION_DIRECTORY = "CONFIGURATION_DIRECTORY";
// private final static String ENV_CACHE_DIRECTORY = "CACHE_DIRECTORY";
private final static long RUNTIME_SHUTDOWN_TIMEOUT = 60 * 1000;
- private Path baseConfigArea;
- private Path baseWritableArea;
private Map<String, String> configuration = new HashMap<>();
- private Map<String, OsgiRuntimeContext> runtimeContexts = new TreeMap<>();
+ RuntimeManagerMain(Path configArea, Path writableArea) {
+// RuntimeManager.loadConfig(configArea, configuration);
+
+ // integration with OSGi runtime; this will be read by the init bundle
+// configuration.put(ServiceMain.PROP_ARGEO_INIT_MAIN, "true");
+ RuntimeManager.loadDefaults(configuration);
+
+ configuration.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA, configArea.toUri().toString());
+ configuration.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA_RO, "true");
+ configuration.put(InitConstants.PROP_OSGI_USE_SYSTEM_PROPERTIES, "false");
- RuntimeManagerMain(Path configArea, Path stateArea) {
- RuntimeManager.loadConfig(configArea, configuration);
- configuration.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, stateArea.resolve(STATE).toUri().toString());
+ configuration.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA,
+ writableArea.resolve(RuntimeManager.STATE).toUri().toString());
// use config area if instance area is not set
if (!configuration.containsKey(InitConstants.PROP_OSGI_INSTANCE_AREA))
- configuration.put(InitConstants.PROP_OSGI_INSTANCE_AREA, stateArea.resolve(DATA).toUri().toString());
- this.baseConfigArea = configArea.getParent();
- this.baseWritableArea = stateArea.getParent();
+ configuration.put(InitConstants.PROP_OSGI_INSTANCE_AREA,
+ writableArea.resolve(RuntimeManager.DATA).toUri().toString());
logger.log(Level.TRACE, () -> "Runtime manager configuration: " + configuration);
}
public void run() {
- OsgiRuntimeContext managerRuntimeContext = new OsgiRuntimeContext(configuration);
+ OsgiRuntimeContext managerRuntimeContext = new OsgiRuntimeContext(OsgiRuntimeContext.loadFrameworkFactory(),
+ configuration);
try {
managerRuntimeContext.run();
InternalState.setMainRuntimeContext(managerRuntimeContext);
// shutdown on exit
Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdown(), "Runtime shutdown"));
- BundleContext bc = managerRuntimeContext.getFramework().getBundleContext();
- // uninstall init as a bundle since it will be available via OSGi system
- OsgiBoot.uninstallBundles(bc, SYMBOLIC_NAME_INIT);
- bc.registerService(RuntimeManager.class, this, new Hashtable<>(configuration));
+// BundleContext bc = managerRuntimeContext.getFramework().getBundleContext();
+// // uninstall init as a bundle since it will be available via OSGi system
+// OsgiBoot.uninstallBundles(bc, SYMBOLIC_NAME_INIT);
+// bc.registerService(RuntimeManager.class, this, new Hashtable<>(configuration));
logger.log(Level.DEBUG, "Registered runtime manager");
managerRuntimeContext.waitForStop(0);
}
protected void shutdown() {
- // shutdowm runtimes
- Map<String, RuntimeContext> shutdowning = new HashMap<>(runtimeContexts);
- for (String id : new HashSet<>(runtimeContexts.keySet())) {
- logger.log(Logger.Level.DEBUG, "Shutting down runtime " + id + " ...");
- closeRuntime(id, true);
- }
- for (String id : shutdowning.keySet())
- try {
- RuntimeContext runtimeContext = shutdowning.get(id);
- runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
- } catch (InterruptedException e) {
- // silent
- } catch (Exception e) {
- logger.log(Logger.Level.DEBUG, "Cannot wait for " + id + " to shutdown", e);
- }
// shutdown manager runtime
try {
InternalState.getMainRuntimeContext().close();
}
}
- OsgiRuntimeContext loadRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
- closeRuntime(relPath, false);
- Path writableArea = baseWritableArea.resolve(relPath);
- Path configArea = baseConfigArea.resolve(relPath);
- Map<String, String> config = new HashMap<>();
- RuntimeManager.loadConfig(configArea, config);
- config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, writableArea.resolve(STATE).toUri().toString());
-
- if (configCallback != null)
- configCallback.accept(config);
-
- // use config area if instance area is not set
- if (!config.containsKey(InitConstants.PROP_OSGI_INSTANCE_AREA))
- config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, writableArea.resolve(DATA).toUri().toString());
-
- OsgiRuntimeContext runtimeContext = new OsgiRuntimeContext(config);
- runtimeContexts.put(relPath, runtimeContext);
- return runtimeContext;
- }
-
- public void startRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
- OsgiRuntimeContext runtimeContext = loadRuntime(relPath, configCallback);
- runtimeContext.run();
- Framework framework = runtimeContext.getFramework();
- if (framework != null) {// in case the framework has closed very quickly after run
- framework.getBundleContext().addFrameworkListener((e) -> {
- if (e.getType() >= FrameworkEvent.STOPPED) {
- logger.log(Level.DEBUG, "Externally stopped runtime " + relPath + ". Unregistering...", e);
- runtimeContexts.remove(relPath);
- }
- });
- } else {
- closeRuntime(relPath, false);
- }
- }
-
- public void closeRuntime(String relPath, boolean async) {
- if (!runtimeContexts.containsKey(relPath))
- return;
- RuntimeContext runtimeContext = runtimeContexts.get(relPath);
- try {
- runtimeContext.close();
- if (!async) {
- runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
- System.gc();
- }
- } catch (Exception e) {
- logger.log(Level.ERROR, "Cannot close runtime context " + relPath, e);
- } finally {
- runtimeContexts.remove(relPath);
- }
-
- }
-
public static void main(String[] args) {
ThinLoggerFinder.reloadConfiguration();
logger.log(Logger.Level.DEBUG, () -> "Argeo Init starting with PID " + ProcessHandle.current().pid());
Map<String, String> env = System.getenv();
-// for (String envName : new TreeSet<>(env.keySet())) {
-// System.out.format("%s=%s%n", envName, env.get(envName));
-// }
- if (args.length < 1)
- throw new IllegalArgumentException("A relative configuration directory must be specified");
- Path configArea = Paths.get(System.getProperty("user.dir"), args[0]);
+
+// if (args.length < 1)
+// throw new IllegalArgumentException("A relative configuration directory must be specified");
+// Path configArea = Paths.get(System.getProperty("user.dir"), args[0]);
// System.out.println("## Start with PID " + ProcessHandle.current().pid());
// System.out.println("user.dir=" + System.getProperty("user.dir"));
- Path stateArea = Paths.get(env.get(ENV_STATE_DIRECTORY));
-
- RuntimeManagerMain runtimeManager = new RuntimeManagerMain(configArea, stateArea);
+ Path writableArea = Paths.get(env.get(ENV_STATE_DIRECTORY));
+ Path configArea = Paths.get(env.get(ENV_CONFIGURATION_DIRECTORY));
+ RuntimeManagerMain runtimeManager = new RuntimeManagerMain(configArea, writableArea);
runtimeManager.run();
}
final static String FILE_SYSTEM_PROPERTIES = "system.properties";
+ @Deprecated
public final static String PROP_ARGEO_INIT_MAIN = "argeo.init.main";
// private static RuntimeContext runtimeContext = null;
config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, dataArea);
// config.put(OsgiBoot.PROP_OSGI_USE_SYSTEM_PROPERTIES, "true");
- OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext(config);
+ OsgiRuntimeContext osgiRuntimeContext = new OsgiRuntimeContext(
+ OsgiRuntimeContext.loadFrameworkFactory(), config);
osgiRuntimeContext.run();
InternalState.setMainRuntimeContext(osgiRuntimeContext);
for (Runnable run : postStart) {
+++ /dev/null
-package org.argeo.init.osgi;
-
-import java.lang.System.Logger;
-import java.lang.System.Logger.Level;
-import java.util.Objects;
-
-import org.argeo.init.ServiceMain;
-import org.argeo.init.logging.ThinLoggerFinder;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-/**
- * An OSGi configurator. See
- * <a href="http://wiki.eclipse.org/Configurator">http:
- * //wiki.eclipse.org/Configurator</a>
- */
-public class Activator implements BundleActivator {
- static {
- // must be called first
- ThinLoggerFinder.lazyInit();
- }
- private final static Logger logger = System.getLogger(Activator.class.getName());
-
- private Long checkpoint = null;
-
- private boolean argeoInit = false;
- /** Not null if we created it ourselves. */
- private OsgiRuntimeContext runtimeContext;
-
- public void start(final BundleContext bundleContext) throws Exception {
- // The OSGi runtime was created by us, and therefore already initialized
- argeoInit = Boolean.parseBoolean(bundleContext.getProperty(ServiceMain.PROP_ARGEO_INIT_MAIN));
- if (!argeoInit) {
- if (runtimeContext == null) {
- runtimeContext = new OsgiRuntimeContext(bundleContext);
- logger.log(Level.DEBUG, () -> "Argeo init via OSGi activator");
- }
-
- // admin thread
-// Thread adminThread = new AdminThread(bundleContext);
-// adminThread.start();
-
- // bootstrap
-// OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
- if (checkpoint == null) {
-// osgiBoot.bootstrap();
- checkpoint = System.currentTimeMillis();
- } else {
- runtimeContext.update();
- checkpoint = System.currentTimeMillis();
- }
- }
- }
-
- public void stop(BundleContext context) throws Exception {
- if (!argeoInit) {
- Objects.nonNull(runtimeContext);
- runtimeContext.stop(context);
- runtimeContext = null;
- }
- }
-
-}
--- /dev/null
+package org.argeo.init.osgi;
+
+import java.util.Optional;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ * A {@link ClassLoader} based on a {@link Bundle} from another OSGi runtime.
+ */
+class ForeignBundleClassLoader extends ClassLoader {// implements BundleReference {
+ private BundleContext localBundleContext;
+ private Bundle foreignBundle;
+
+ public ForeignBundleClassLoader(BundleContext localBundleContext, Bundle foreignBundle) {
+ super("Foreign bundle " + foreignBundle.toString(), Optional.ofNullable(foreignBundle.adapt(BundleWiring.class))
+ .map((bw) -> bw.getClassLoader()).orElse(null));
+ this.localBundleContext = localBundleContext;
+ this.foreignBundle = foreignBundle;
+ }
+
+// @Override
+ protected Bundle getBundle() {
+ return localBundleContext.getBundle(foreignBundle.getLocation());
+ }
+
+// @Override
+// public URL getResource(String resName) {
+// URL res = super.getResource(resName);
+// return res;
+// }
+//
+// @Override
+// protected URL findResource(String resName) {
+// Bundle localBundle = getBundle();
+// if (localBundle != null) {
+// URL res = localBundle.getEntry(resName);
+// if (res != null)
+// return res;
+// }
+// return null;
+// }
+
+}
--- /dev/null
+package org.argeo.init.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.connect.ConnectContent;
+
+/**
+ * A {@link ConnectContent} based on a {@link Bundle} from another OSGi runtime.
+ */
+class ForeignBundleConnectContent implements ConnectContent {
+ private final Bundle foreignBundle;
+ private final ClassLoader classLoader;
+
+ public ForeignBundleConnectContent(BundleContext localBundleContext, Bundle foreignBundle) {
+ this.foreignBundle = foreignBundle;
+ this.classLoader = new ForeignBundleClassLoader(localBundleContext, foreignBundle);
+ }
+
+ @Override
+ public Optional<Map<String, String>> getHeaders() {
+ Dictionary<String, String> dict = foreignBundle.getHeaders();
+ List<String> keys = Collections.list(dict.keys());
+ Map<String, String> dictCopy = keys.stream().collect(Collectors.toMap(Function.identity(), dict::get));
+ return Optional.of(dictCopy);
+ }
+
+ @Override
+ public Iterable<String> getEntries() throws IOException {
+ List<String> lst = Collections.list(foreignBundle.findEntries("", "*", true)).stream().map((u) -> u.getPath())
+ .toList();
+ return lst;
+ }
+
+ @Override
+ public Optional<ConnectEntry> getEntry(String path) {
+ URL u = foreignBundle.getEntry(path);
+ if (u == null) {
+ u = foreignBundle.getEntry("bin/" + path);
+ // System.err.println(u2);
+ }
+ if (u == null) {
+ if ("plugin.xml".equals(path))
+ return Optional.empty();
+ if (path.startsWith("META-INF/versions/"))
+ return Optional.empty();
+ System.err.println(foreignBundle.getSymbolicName() + " " + path + " not found");
+ return Optional.empty();
+ }
+ URL url = u;
+ ConnectEntry urlConnectEntry = new ConnectEntry() {
+
+ @Override
+ public String getName() {
+ return path;
+ }
+
+ @Override
+ public long getLastModified() {
+ return foreignBundle.getLastModified();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return url.openStream();
+ }
+
+ @Override
+ public long getContentLength() {
+ return -1;
+ }
+ };
+ return Optional.of(urlConnectEntry);
+ }
+
+ @Override
+ public Optional<ClassLoader> getClassLoader() {
+ ClassLoader cl;
+ // cl = bundle.adapt(BundleWiring.class).getClassLoader();
+
+ // cl = subFrameworkClassLoader;
+ cl = classLoader;
+ return Optional.of(cl);
+// return Optional.empty();
+ }
+
+ @Override
+ public void open() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+
+ }
+
+}
--- /dev/null
+package org.argeo.init.osgi;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.connect.ConnectContent;
+import org.osgi.framework.connect.ConnectModule;
+import org.osgi.framework.connect.ModuleConnector;
+
+/**
+ * A {@link ModuleConnector} based on another OSGi runtime.
+ */
+class ForeignModuleConnector implements ModuleConnector {
+ private final BundleContext foreignBundleContext;
+ private final List<String> foreignCategories;
+
+ private BundleContext localBundleContext;
+
+ public ForeignModuleConnector(BundleContext foreignBundleContext, List<String> foreignCategories) {
+ this.foreignBundleContext = foreignBundleContext;
+ this.foreignCategories = foreignCategories;
+ }
+
+ @Override
+ public Optional<BundleActivator> newBundleActivator() {
+ return Optional.of(new BundleActivator() {
+ @Override
+ public void start(BundleContext context) throws Exception {
+ ForeignModuleConnector.this.localBundleContext = context;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ ForeignModuleConnector.this.localBundleContext = null;
+ }
+
+ });
+ }
+
+ @Override
+ public void initialize(File storage, Map<String, String> configuration) {
+ }
+
+ @Override
+ public Optional<ConnectModule> connect(String location) throws BundleException {
+ // hacks
+ if (location.contains("org.eclipse.rap.rwt.osgi"))
+ return Optional.empty();
+
+ String category = categoryFromLocation(location);
+ if (category == null || !foreignCategories.contains(category))
+ return Optional.empty();
+ Bundle bundle = foreignBundleContext.getBundle(location);
+ if (bundle != null && bundle.getBundleId() != 0) {
+ // System.out.println("Foreign Bundle: " + bundle.getSymbolicName() + " " +
+ // location);
+ ConnectModule module = new ConnectModule() {
+
+ @Override
+ public ConnectContent getContent() throws IOException {
+ return new ForeignBundleConnectContent(localBundleContext, bundle);
+ }
+ };
+ return Optional.of(module);
+ }
+ return Optional.empty();
+ }
+
+ protected String categoryFromLocation(String location) {
+ // deal with Windows (sigh)
+ String regexp = File.separatorChar == '\\' ? "\\\\" : "/";
+ String[] arr = location.split(regexp);
+ if (arr.length < 2)
+ return null;
+ // TODO make it more robust
+ String category = arr[arr.length - 2];
+ return category;
+ }
+}
--- /dev/null
+package org.argeo.init.osgi;
+
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
+
+import org.argeo.api.init.RuntimeManager;
+import org.argeo.init.logging.ThinLoggerFinder;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
+import org.osgi.framework.launch.Framework;
+
+/**
+ * An OSGi configurator. See
+ * <a href="http://wiki.eclipse.org/Configurator">http:
+ * //wiki.eclipse.org/Configurator</a>
+ */
+public class InitActivator implements BundleActivator {
+ static {
+ // must be called first
+ ThinLoggerFinder.lazyInit();
+ }
+ private final static Logger logger = System.getLogger(InitActivator.class.getName());
+
+ private Long checkpoint = null;
+
+ // TODO use framework factory SR
+// @Deprecated
+// private boolean argeoInit = false;
+ /** Not null if we created it ourselves. */
+ private OsgiRuntimeContext runtimeContext;
+ private ServiceRegistration<ConnectFrameworkFactory> frameworkFactorySr = null;
+
+ private static OsgiRuntimeManager runtimeManager;
+
+ public void start(final BundleContext bundleContext) throws Exception {
+ ConnectFrameworkFactory frameworkFactory = OsgiRuntimeContext.getFrameworkFactory(bundleContext);
+ if (frameworkFactory == null) {
+// argeoInit = false;
+ frameworkFactory = newFrameworkFactory();
+ frameworkFactorySr = bundleContext.registerService(ConnectFrameworkFactory.class, frameworkFactory, null);
+ }
+
+ // The OSGi runtime was created by us, and therefore already initialized
+// argeoInit = Boolean.parseBoolean(bundleContext.getProperty(ServiceMain.PROP_ARGEO_INIT_MAIN));
+ if (!isArgeoInit()) {
+ if (runtimeContext == null) {
+ runtimeContext = new OsgiRuntimeContext(bundleContext);
+ logger.log(Level.DEBUG, () -> "Argeo init via OSGi activator");
+ }
+
+ // admin thread
+// Thread adminThread = new AdminThread(bundleContext);
+// adminThread.start();
+
+ // bootstrap
+// OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
+ if (checkpoint == null) {
+// osgiBoot.bootstrap();
+ checkpoint = System.currentTimeMillis();
+ } else {
+ runtimeContext.update();
+ checkpoint = System.currentTimeMillis();
+ }
+ } else {
+
+ if (runtimeManager != null)
+ throw new IllegalArgumentException("Runtime manager is already set");
+ runtimeManager = new OsgiRuntimeManager(bundleContext);
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ if (!isArgeoInit()) {
+ frameworkFactorySr.unregister();
+ Objects.nonNull(runtimeContext);
+ runtimeContext.stop(context);
+ runtimeContext = null;
+ }
+ runtimeManager = null;
+ }
+
+ /** Whether it wa sinitialised by an Argeo Init main class. */
+ private boolean isArgeoInit() {
+ return frameworkFactorySr == null;
+ }
+
+ public static RuntimeManager getRuntimeManager() {
+ return runtimeManager;
+ }
+
+ /**
+ * Workaround to explicitly instantiate an Equinox
+ * {@link ConnectFrameworkFactory} when running in a pure OSGi runtime.
+ */
+ private ConnectFrameworkFactory newFrameworkFactory() {
+ final String EQUINOX_FRAMEWORK_FACTORY_CLASS = "org.eclipse.osgi.launch.EquinoxFactory";
+ try {
+ @SuppressWarnings("unchecked")
+ Class<? extends ConnectFrameworkFactory> frameworkFactoryClass = (Class<? extends ConnectFrameworkFactory>) Framework.class
+ .getClassLoader().loadClass(EQUINOX_FRAMEWORK_FACTORY_CLASS);
+ return frameworkFactoryClass.getConstructor().newInstance();
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException("Cannot create OSGi framework factory", e);
+ }
+ }
+}
public void install() {
String osgiInstancePath = getProperty(InitConstants.PROP_OSGI_INSTANCE_AREA);
String osgiConfigurationPath = getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA);
- String osgiSharedConfigurationPath = getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA);
+ String osgiSharedConfigurationPath = getProperty(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA);
logger.log(DEBUG, () -> "OSGi bootstrap starting" //
+ (osgiInstancePath != null ? " data: " + osgiInstancePath + "" : "") //
+ (osgiConfigurationPath != null ? " state: " + osgiConfigurationPath + "" : "") //
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
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);
+ }
}
--- /dev/null
+package org.argeo.init.osgi;
+
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+
+import org.argeo.api.init.InitConstants;
+import org.argeo.api.init.RuntimeContext;
+import org.argeo.api.init.RuntimeManager;
+import org.argeo.internal.init.InternalState;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
+import org.osgi.framework.launch.Framework;
+
+/**
+ * Dynamically configures and launches multiple runtimes.
+ */
+class OsgiRuntimeManager implements RuntimeManager {
+ private final static Logger logger = System.getLogger(OsgiRuntimeManager.class.getName());
+
+ private final static long RUNTIME_SHUTDOWN_TIMEOUT = 60 * 1000;
+
+// private Path ownConfigArea;
+
+ private Path baseConfigArea;
+ private Path baseWritableArea;
+// private Map<String, String> configuration = new HashMap<>();
+
+ private ConnectFrameworkFactory frameworkFactory;
+
+ private final BundleContext bundleContext;
+
+ private Map<String, OsgiRuntimeContext> runtimeContexts = new TreeMap<>();
+
+ private boolean useForeignRuntime = Boolean
+ .parseBoolean(System.getProperty(InitConstants.PROP_ARGEO_OSGI_EXPORT_ENABLED, "true"));
+
+ OsgiRuntimeManager(BundleContext bundleContext) {
+ Objects.requireNonNull(bundleContext);
+ this.bundleContext = bundleContext;
+ frameworkFactory = OsgiRuntimeContext.getFrameworkFactory(bundleContext);
+ this.baseConfigArea = Paths
+ .get(URI.create(bundleContext.getProperty(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA)));
+// this.baseConfigArea = ownConfigArea.getParent();
+ this.baseWritableArea = Paths
+ .get(URI.create(bundleContext.getProperty(InitConstants.PROP_OSGI_CONFIGURATION_AREA))).getParent();
+
+// logger.log(Level.TRACE, () -> "Runtime manager configuration: " + configuration);
+
+// System.out.println("java.library.path=" + System.getProperty("java.library.path"));
+ }
+
+ protected void shutdown() {
+ // shutdown runtimes
+ Map<String, RuntimeContext> shutdowning = new HashMap<>(runtimeContexts);
+ for (String id : new HashSet<>(runtimeContexts.keySet())) {
+ logger.log(Logger.Level.DEBUG, "Shutting down runtime " + id + " ...");
+ closeRuntime(id, true);
+ }
+ for (String id : shutdowning.keySet())
+ try {
+ RuntimeContext runtimeContext = shutdowning.get(id);
+ runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
+ } catch (InterruptedException e) {
+ // silent
+ } catch (Exception e) {
+ logger.log(Logger.Level.DEBUG, "Cannot wait for " + id + " to shutdown", e);
+ }
+ // shutdown manager runtime
+ try {
+ InternalState.getMainRuntimeContext().close();
+ InternalState.getMainRuntimeContext().waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
+// logger.log(Logger.Level.INFO, "Argeo Init stopped with PID " + ProcessHandle.current().pid());
+ System.out.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ Runtime.getRuntime().halt(1);
+ }
+ }
+
+ OsgiRuntimeContext loadRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
+ closeRuntime(relPath, false);
+
+ BundleContext foreignBundleContext = null;
+ if (useForeignRuntime) {
+ foreignBundleContext = bundleContext;
+
+ Path parentRelPath = Paths.get(relPath).getParent();
+ if (parentRelPath != null && Files.exists(baseConfigArea.resolve(parentRelPath))) {
+ if (!runtimeContexts.containsKey(parentRelPath.toString())) {
+
+ String exportCategories = bundleContext
+ .getProperty(InitConstants.PROP_ARGEO_OSGI_EXPORT_CATEGORIES);
+ List<String> foreignCategories = exportCategories == null ? new ArrayList<>()
+ : Arrays.asList(exportCategories.trim().split(","));
+ Path writableArea = baseWritableArea.resolve(parentRelPath);
+ Path configArea = baseConfigArea.resolve(parentRelPath);
+ Map<String, String> config = new HashMap<>();
+ RuntimeManager.loadDefaults(config);
+ config.put(InitConstants.PROP_OSGI_USE_SYSTEM_PROPERTIES, "false");
+ config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA,
+ writableArea.resolve(STATE).toUri().toString());
+ config.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA, configArea.toUri().toString());
+ config.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA_RO, "true");
+ OsgiRuntimeContext runtimeContext = new OsgiRuntimeContext(frameworkFactory, config,
+ foreignBundleContext, foreignCategories);
+ runtimeContexts.put(parentRelPath.toString(), runtimeContext);
+ runtimeContext.run();
+ // FIXME properly stage installation
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // silent
+ }
+ }
+ OsgiRuntimeContext parentRuntimeContext = runtimeContexts.get(parentRelPath.toString());
+ foreignBundleContext = parentRuntimeContext.getFramework().getBundleContext();
+ }
+ }
+ Path writableArea = baseWritableArea.resolve(relPath);
+ Path configArea = baseConfigArea.resolve(relPath).getParent().resolve(SHARED);
+ Map<String, String> config = new HashMap<>();
+// RuntimeManager.loadConfig(configArea, config);
+ RuntimeManager.loadDefaults(config);
+ config.put(InitConstants.PROP_OSGI_USE_SYSTEM_PROPERTIES, "false");
+ config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, writableArea.resolve(STATE).toUri().toString());
+ config.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA, configArea.toUri().toString());
+ config.put(InitConstants.PROP_OSGI_SHARED_CONFIGURATION_AREA_RO, "true");
+
+ if (configCallback != null)
+ configCallback.accept(config);
+
+ // use config area if instance area is not set
+ if (!config.containsKey(InitConstants.PROP_OSGI_INSTANCE_AREA))
+ config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, writableArea.resolve(DATA).toUri().toString());
+
+ // create framework
+ OsgiRuntimeContext runtimeContext;
+ if (useForeignRuntime) {
+ String exportCategories = bundleContext.getProperty(InitConstants.PROP_ARGEO_OSGI_EXPORT_CATEGORIES);
+ List<String> foreignCategories = exportCategories == null ? new ArrayList<>()
+ : Arrays.asList(exportCategories.trim().split(","));
+ runtimeContext = new OsgiRuntimeContext(frameworkFactory, config, foreignBundleContext, foreignCategories);
+ } else {
+ runtimeContext = new OsgiRuntimeContext(frameworkFactory, config);
+ }
+ runtimeContexts.put(relPath, runtimeContext);
+ return runtimeContext;
+ }
+
+ public void startRuntime(String relPath, Consumer<Map<String, String>> configCallback) {
+ OsgiRuntimeContext runtimeContext = loadRuntime(relPath, configCallback);
+ runtimeContext.run();
+ Framework framework = runtimeContext.getFramework();
+ if (framework != null) {// in case the framework has closed very quickly after run
+ framework.getBundleContext().addFrameworkListener((e) -> {
+ if (e.getType() >= FrameworkEvent.STOPPED) {
+ logger.log(Level.DEBUG, "Externally stopped runtime " + relPath + ". Unregistering...", e);
+ runtimeContexts.remove(relPath);
+ }
+ });
+ } else {
+ closeRuntime(relPath, false);
+ }
+ }
+
+ public void closeRuntime(String relPath, boolean async) {
+ if (!runtimeContexts.containsKey(relPath))
+ return;
+ RuntimeContext runtimeContext = runtimeContexts.get(relPath);
+ try {
+ runtimeContext.close();
+ if (!async) {
+ runtimeContext.waitForStop(RUNTIME_SHUTDOWN_TIMEOUT);
+ System.gc();
+ }
+ } catch (Exception e) {
+ logger.log(Level.ERROR, "Cannot close runtime context " + relPath, e);
+ } finally {
+ runtimeContexts.remove(relPath);
+ }
+
+ }
+}
import static java.lang.System.Logger.Level.INFO;
-import java.io.File;
-import java.io.IOException;
import java.io.InputStream;
import java.lang.System.Logger;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
-import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.UUID;
-import java.util.function.Function;
-import java.util.stream.Collectors;
import org.argeo.api.init.InitConstants;
import org.argeo.api.init.RuntimeManager;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
-import org.osgi.framework.connect.ConnectContent;
import org.osgi.framework.connect.ConnectFrameworkFactory;
-import org.osgi.framework.connect.ConnectModule;
import org.osgi.framework.connect.ModuleConnector;
import org.osgi.framework.launch.Framework;
-import org.osgi.framework.wiring.BundleWiring;
public class SubFrameworkActivator implements BundleActivator {
private final static Logger logger = System.getLogger(SubFrameworkActivator.class.getName());
.getClassLoader().loadClass(EQUINOX_FRAMEWORK_FACTORY_CLASS);
frameworkFactory = frameworkFactoryClass.getConstructor().newInstance();
- boolean test = true;
+ boolean test = false;
if (test)
new Thread() {
// config.put("osgi.parentClassLoader", "app");
// config.put("osgi.contextClassLoaderParent", "app");
- ModuleConnector moduleConnector = new ParentBundleModuleConnector(foreignBundleContext);
+ ModuleConnector moduleConnector = new ForeignModuleConnector(foreignBundleContext, null);
// URL frameworkUrl = URI.create(bundleContext.getProperty("osgi.framework")).toURL();
// URLClassLoader frameworkClassLoader = new URLClassLoader(new URL[] { frameworkUrl, });
frameworkFactory = null;
}
- static class ParentBundleModuleConnector implements ModuleConnector {
- private final BundleContext foreignBundleContext;
- private BundleContext localBundleContext;
-
- public ParentBundleModuleConnector(BundleContext foreignBundleContext) {
- this.foreignBundleContext = foreignBundleContext;
- }
-
- @Override
- public Optional<BundleActivator> newBundleActivator() {
- return Optional.of(new BundleActivator() {
- @Override
- public void start(BundleContext context) throws Exception {
- ParentBundleModuleConnector.this.localBundleContext = context;
- }
-
- @Override
- public void stop(BundleContext context) throws Exception {
- ParentBundleModuleConnector.this.localBundleContext = null;
- }
-
- });
- }
-
- @Override
- public void initialize(File storage, Map<String, String> configuration) {
- }
-
- @Override
- public Optional<ConnectModule> connect(String location) throws BundleException {
- Bundle bundle = foreignBundleContext.getBundle(location);
- if (bundle != null && bundle.getBundleId() != 0) {
- // System.out.println("Foreign Bundle: " + bundle.getSymbolicName() + " " +
- // location);
- ConnectModule module = new ConnectModule() {
-
- @Override
- public ConnectContent getContent() throws IOException {
- return new ForeignBundleConnectContent(localBundleContext, bundle);
- }
- };
- return Optional.of(module);
- }
- return Optional.empty();
- }
- }
-
- static class ForeignBundleClassLoader extends ClassLoader {// implements BundleReference {
- private BundleContext localBundleContext;
- private Bundle foreignBundle;
-
- public ForeignBundleClassLoader(BundleContext localBundleContext, Bundle foreignBundle) {
- super("Foreign bundle " + foreignBundle.toString(), Optional
- .ofNullable(foreignBundle.adapt(BundleWiring.class)).map((bw) -> bw.getClassLoader()).orElse(null));
- this.localBundleContext = localBundleContext;
- this.foreignBundle = foreignBundle;
- }
-
-// @Override
- protected Bundle getBundle() {
- return localBundleContext.getBundle(foreignBundle.getLocation());
- }
-
-// @Override
-// public URL getResource(String resName) {
-// URL res = super.getResource(resName);
-// return res;
-// }
-//
-// @Override
-// protected URL findResource(String resName) {
-// Bundle localBundle = getBundle();
-// if (localBundle != null) {
-// URL res = localBundle.getEntry(resName);
-// if (res != null)
-// return res;
-// }
-// return null;
-// }
-
- }
-
- static class ForeignBundleConnectContent implements ConnectContent {
- private final Bundle foreignBundle;
- private final ClassLoader classLoader;
-
- public ForeignBundleConnectContent(BundleContext localBundleContext, Bundle foreignBundle) {
- this.foreignBundle = foreignBundle;
- this.classLoader = new ForeignBundleClassLoader(localBundleContext, foreignBundle);
- }
-
- @Override
- public Optional<Map<String, String>> getHeaders() {
- Dictionary<String, String> dict = foreignBundle.getHeaders();
- List<String> keys = Collections.list(dict.keys());
- Map<String, String> dictCopy = keys.stream().collect(Collectors.toMap(Function.identity(), dict::get));
- return Optional.of(dictCopy);
- }
-
- @Override
- public Iterable<String> getEntries() throws IOException {
- List<String> lst = Collections.list(foreignBundle.findEntries("", "*", true)).stream()
- .map((u) -> u.getPath()).toList();
- return lst;
- }
-
- @Override
- public Optional<ConnectEntry> getEntry(String path) {
- URL u = foreignBundle.getEntry(path);
- if (u == null) {
- u = foreignBundle.getEntry("bin/" + path);
- // System.err.println(u2);
- }
- if (u == null) {
- if ("plugin.xml".equals(path))
- return Optional.empty();
- if (path.startsWith("META-INF/versions/"))
- return Optional.empty();
- System.err.println(foreignBundle.getSymbolicName() + " " + path + " not found");
- return Optional.empty();
- }
- URL url = u;
- ConnectEntry urlConnectEntry = new ConnectEntry() {
-
- @Override
- public String getName() {
- return path;
- }
-
- @Override
- public long getLastModified() {
- return foreignBundle.getLastModified();
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- return url.openStream();
- }
-
- @Override
- public long getContentLength() {
- return -1;
- }
- };
- return Optional.of(urlConnectEntry);
- }
-
- @Override
- public Optional<ClassLoader> getClassLoader() {
- ClassLoader cl;
- // cl = bundle.adapt(BundleWiring.class).getClassLoader();
-
- // cl = subFrameworkClassLoader;
- cl = classLoader;
- return Optional.of(cl);
-// return Optional.empty();
- }
-
- @Override
- public void open() throws IOException {
- }
-
- @Override
- public void close() throws IOException {
-
- }
-
- }
}
-Subproject commit ec9a0b67c92105fc42ec14cdbec7ff9464c6cc3c
+Subproject commit c5ce5217b5433d7470628c1ccb90141a028d3378
public void stop() {
dispose();
if (display != null) {
- display.dispose();
- display = null;
+ display.syncExec(() -> {
+ display.dispose();
+ display = null;
+ });
}
}
}
public void dispose() {
- if (!rootShell.isDisposed())
- rootShell.dispose();
+ if (!rootShell.isDisposed()) {
+ rootShell.getDisplay().syncExec(() -> {
+ rootShell.dispose();
+ });
+ }
}
protected boolean isFullscreen() {
org.eclipse.jface.dialogs,\
org.eclipse.swt.events,\
javax.servlet.http;version="[3,5)",\
+java.awt.*;resolution:=optional,\
*
org.eclipse.swt,\
javax.servlet.http;resolution:=optional,\
javax.servlet;resolution:=optional,\
+java.awt.*;resolution:=optional,\
+javax.swing.*;resolution:=optional,\
+org.eclipse.swt.awt.*;resolution:=optional,\
*
Export-Package: org.argeo.*,\