X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Finit%2Fosgi%2FSubFrameworkActivator.java;fp=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Finit%2Fosgi%2FSubFrameworkActivator.java;h=3d6469df84d96b3215939464015d5b1a94e2dc87;hb=641e3f3c535f540afd122d2a7b53389342f77002;hp=0000000000000000000000000000000000000000;hpb=7d4cccc2f758f30e0704f2e8f500c43fd4245ebf;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.init/src/org/argeo/init/osgi/SubFrameworkActivator.java b/org.argeo.init/src/org/argeo/init/osgi/SubFrameworkActivator.java new file mode 100644 index 000000000..3d6469df8 --- /dev/null +++ b/org.argeo.init/src/org/argeo/init/osgi/SubFrameworkActivator.java @@ -0,0 +1,295 @@ +package org.argeo.init.osgi; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +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.List; +import java.util.Map; +import java.util.Optional; +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.BundleReference; +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 String EQUINOX_FRAMEWORK_CLASS = "org.eclipse.osgi.launch.Equinox"; + private final static String EQUINOX_FRAMEWORK_FACTORY_CLASS = "org.eclipse.osgi.launch.EquinoxFactory"; + +// private ClassLoader bundleClassLoader; +// private ClassLoader subFrameworkClassLoader; + private BundleContext bundleContext; + + private ConnectFrameworkFactory frameworkFactory; + + @Override + public void start(BundleContext context) throws Exception { + this.bundleContext = context; + + try { + Bundle bundle = context.getBundle(); + ClassLoader bundleClassLoader = bundle.adapt(BundleWiring.class).getClassLoader(); +// subFrameworkClassLoader = new URLClassLoader(new URL[0], bundleClassLoader); + + @SuppressWarnings("unchecked") + Class frameworkFactoryClass = (Class) bundleClassLoader + .loadClass(EQUINOX_FRAMEWORK_FACTORY_CLASS); + frameworkFactory = frameworkFactoryClass.getConstructor().newInstance(); + + new Thread() { + + @Override + public void run() { + for (int i = 0; i < 5; i++) { + Map config = new HashMap<>(); + Path basePase = Paths.get(System.getProperty("user.home"), ".config/argeo/test/", "test" + i); + config.put(InitConstants.PROP_OSGI_CONFIGURATION_AREA, + basePase.resolve(RuntimeManager.STATE).toString()); + config.put(InitConstants.PROP_OSGI_INSTANCE_AREA, + basePase.resolve(RuntimeManager.DATA).toString()); + config.put("argeo.host", "host" + i); + config.put("osgi.console", "host" + i + ":2023"); + startFramework(config); + } + } + + }.start(); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + Framework startFramework(Map config) { + try { + URL bundleConfigUrl = bundleContext.getBundle().getEntry("config.ini"); + try (InputStream in = bundleConfigUrl.openStream()) { + RuntimeManager.loadConfig(in, config); + } + + // Equinox +// config.put("osgi.frameworkParentClassloader", "current"); +// config.put("osgi.parentClassLoader", "app"); +// config.put("osgi.contextClassLoaderParent", "app"); + + ModuleConnector moduleConnector = new ParentBundleModuleConnector(bundleContext); + +// URL frameworkUrl = URI.create(bundleContext.getProperty("osgi.framework")).toURL(); +// URLClassLoader frameworkClassLoader = new URLClassLoader(new URL[] { frameworkUrl, }); +// Class frameworkClass = (Class) frameworkClassLoader +// .loadClass(EQUINOX_FRAMEWORK_CLASS); +// Framework framework = frameworkClass.getConstructor(Map.class, ModuleConnector.class).newInstance(config, +// moduleConnector); + + Framework framework = frameworkFactory.newFramework(config, moduleConnector); + + framework.init(); + + for (Bundle b : bundleContext.getBundles()) { + if (b.getBundleId() == 0) + continue; + String location = b.getLocation(); + if (location.contains("/org.argeo.tp/") // + || location.contains("/org.argeo.tp.sys/") // + || location.contains("/org.argeo.tp.httpd/") // + || location.contains("/org.argeo.tp.sshd/") // + || location.contains("/org.argeo.cms/org.argeo.init") // + ) { + framework.getBundleContext().installBundle(b.getLocation()); + } + } + + OsgiBoot osgiBoot = new OsgiBoot(framework.getBundleContext()); + osgiBoot.install(); +// OsgiBoot.uninstallBundles(osgiBoot.getBundleContext(), "org.argeo.api.cms"); +// OsgiBoot.uninstallBundles(osgiBoot.getBundleContext(), "org.osgi.service.useradmin"); +// osgiBoot.getBundleContext() +// .installBundle("initial@reference:file:../../../../../argeo-commons/org.argeo.api.cms/"); +// osgiBoot.getBundleContext().installBundle( +// "reference:file:/usr/local/share/a2/osgi/equinox/org.argeo.tp.osgi/org.osgi.service.useradmin.1.1.jar"); + osgiBoot.refresh(); + framework.start(); + osgiBoot.startBundles(); + +// for (Bundle b : framework.getBundleContext().getBundles()) { +// BundleContext bc = b.getBundleContext(); +// if (bc == null) +// System.err.println(b.getSymbolicName() + " BC null"); +// } + return framework; + } catch (Exception e) { + throw new IllegalStateException("Cannot start framework", e); + } + } + + @Override + public void stop(BundleContext context) throws Exception { + bundleContext = null; + frameworkFactory = null; + } + + class ParentBundleModuleConnector implements ModuleConnector { + private final BundleContext foreignBundleContext; + private BundleContext localBundleContext; + + public ParentBundleModuleConnector(BundleContext foreignBundleContext) { + this.foreignBundleContext = foreignBundleContext; + } + + @Override + public Optional 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 configuration) { + } + + @Override + public Optional 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(); + } + } + + 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 + public Bundle getBundle() { + return localBundleContext.getBundle(foreignBundle.getLocation()); + } + } + + class ForeignBundleConnectContent implements ConnectContent { + private final Bundle bundle; + private final ClassLoader classLoader; + + public ForeignBundleConnectContent(BundleContext localBundleContext, Bundle bundle) { + this.bundle = bundle; + this.classLoader = new ForeignBundleClassLoader(localBundleContext, bundle); + } + + @Override + public Optional> getHeaders() { + Dictionary dict = bundle.getHeaders(); + List keys = Collections.list(dict.keys()); + Map dictCopy = keys.stream().collect(Collectors.toMap(Function.identity(), dict::get)); + return Optional.of(dictCopy); + } + + @Override + public Iterable getEntries() throws IOException { + List lst = Collections.list(bundle.findEntries("", "*", true)).stream().map((u) -> u.getPath()) + .toList(); + return lst; + } + + @Override + public Optional getEntry(String path) { + URL u = bundle.getEntry(path); + if (u == null) { + u = bundle.getEntry("bin/" + path); + // System.err.println(u2); + } + if (u == null) { + if ("plugin.xml".equals(path)) + return Optional.empty(); + System.err.println(bundle.getSymbolicName() + " " + path + " not found"); + return Optional.empty(); + } + URL url = u; + ConnectEntry urlConnectEntry = new ConnectEntry() { + + @Override + public String getName() { + return path; + } + + @Override + public long getLastModified() { + // FIXME + return System.currentTimeMillis(); + } + + @Override + public InputStream getInputStream() throws IOException { + return url.openStream(); + } + + @Override + public long getContentLength() { + return -1; + } + }; + return Optional.of(urlConnectEntry); + } + + @Override + public Optional 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 { + } + + } +}