1 package org
.argeo
.init
.osgi
;
3 import static java
.lang
.System
.Logger
.Level
.INFO
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStream
;
8 import java
.lang
.System
.Logger
;
10 import java
.nio
.file
.Path
;
11 import java
.nio
.file
.Paths
;
12 import java
.util
.Collections
;
13 import java
.util
.Dictionary
;
14 import java
.util
.HashMap
;
15 import java
.util
.Iterator
;
16 import java
.util
.List
;
18 import java
.util
.Optional
;
19 import java
.util
.UUID
;
20 import java
.util
.function
.Function
;
21 import java
.util
.stream
.Collectors
;
23 import org
.argeo
.api
.init
.InitConstants
;
24 import org
.argeo
.api
.init
.RuntimeManager
;
25 import org
.osgi
.framework
.Bundle
;
26 import org
.osgi
.framework
.BundleActivator
;
27 import org
.osgi
.framework
.BundleContext
;
28 import org
.osgi
.framework
.BundleException
;
29 import org
.osgi
.framework
.Constants
;
30 import org
.osgi
.framework
.FrameworkEvent
;
31 import org
.osgi
.framework
.connect
.ConnectContent
;
32 import org
.osgi
.framework
.connect
.ConnectFrameworkFactory
;
33 import org
.osgi
.framework
.connect
.ConnectModule
;
34 import org
.osgi
.framework
.connect
.ModuleConnector
;
35 import org
.osgi
.framework
.launch
.Framework
;
36 import org
.osgi
.framework
.wiring
.BundleWiring
;
38 public class SubFrameworkActivator
implements BundleActivator
{
39 private final static Logger logger
= System
.getLogger(SubFrameworkActivator
.class.getName());
41 // private final static String EQUINOX_FRAMEWORK_CLASS = "org.eclipse.osgi.launch.Equinox";
42 private final static String EQUINOX_FRAMEWORK_FACTORY_CLASS
= "org.eclipse.osgi.launch.EquinoxFactory";
44 // private ClassLoader bundleClassLoader;
45 // private ClassLoader subFrameworkClassLoader;
46 private BundleContext foreignBundleContext
;
48 private ConnectFrameworkFactory frameworkFactory
;
50 private Map
<UUID
, Framework
> subFrameworks
= Collections
.synchronizedMap(new HashMap
<>());
52 private UUID foreignFrameworkUuid
;
55 public void start(BundleContext context
) throws Exception
{
56 this.foreignBundleContext
= context
;
57 foreignFrameworkUuid
= UUID
.fromString(foreignBundleContext
.getProperty(Constants
.FRAMEWORK_UUID
));
60 // Bundle bundle = context.getBundle();
61 // ClassLoader bundleClassLoader = bundle.adapt(BundleWiring.class).getClassLoader();
62 // subFrameworkClassLoader = new URLClassLoader(new URL[0], bundleClassLoader);
64 @SuppressWarnings("unchecked")
65 Class
<?
extends ConnectFrameworkFactory
> frameworkFactoryClass
= (Class
<?
extends ConnectFrameworkFactory
>) Framework
.class
66 .getClassLoader().loadClass(EQUINOX_FRAMEWORK_FACTORY_CLASS
);
67 frameworkFactory
= frameworkFactoryClass
.getConstructor().newInstance();
75 for (int i
= 0; i
< 5; i
++) {
76 Map
<String
, String
> config
= new HashMap
<>();
77 Path basePase
= Paths
.get(System
.getProperty("user.home"), ".config/argeo/test/",
79 config
.put(InitConstants
.PROP_OSGI_CONFIGURATION_AREA
,
80 basePase
.resolve(RuntimeManager
.STATE
).toString());
81 config
.put(InitConstants
.PROP_OSGI_INSTANCE_AREA
,
82 basePase
.resolve(RuntimeManager
.DATA
).toString());
83 config
.put("argeo.host", "host" + i
);
84 config
.put("osgi.console", "host" + i
+ ":2023");
85 createFramework(config
);
90 } catch (Exception e
) {
96 Framework
createFramework(Map
<String
, String
> config
) {
98 URL bundleConfigUrl
= foreignBundleContext
.getBundle().getEntry("config.ini");
99 try (InputStream in
= bundleConfigUrl
.openStream()) {
100 RuntimeManager
.loadConfig(in
, config
);
104 // config.put("osgi.frameworkParentClassloader", "current");
105 // config.put("osgi.parentClassLoader", "app");
106 // config.put("osgi.contextClassLoaderParent", "app");
108 ModuleConnector moduleConnector
= new ParentBundleModuleConnector(foreignBundleContext
);
110 // URL frameworkUrl = URI.create(bundleContext.getProperty("osgi.framework")).toURL();
111 // URLClassLoader frameworkClassLoader = new URLClassLoader(new URL[] { frameworkUrl, });
112 // Class<? extends Framework> frameworkClass = (Class<? extends Framework>) frameworkClassLoader
113 // .loadClass(EQUINOX_FRAMEWORK_CLASS);
114 // Framework framework = frameworkClass.getConstructor(Map.class, ModuleConnector.class).newInstance(config,
117 config
.put(InitConstants
.PROP_ARGEO_OSGI_PARENT_UUID
, foreignFrameworkUuid
.toString());
118 Framework framework
= frameworkFactory
.newFramework(config
, moduleConnector
);
120 framework
.init((e
) -> {
121 UUID frameworkUuid
= UUID
122 .fromString(framework
.getBundleContext().getProperty(Constants
.FRAMEWORK_UUID
));
123 if (e
.getType() == FrameworkEvent
.STOPPED
) {
124 subFrameworks
.remove(frameworkUuid
);
125 logger
.log(INFO
, "Removed subframework " + frameworkUuid
+ " in parent " + foreignFrameworkUuid
);
129 for (Bundle b
: foreignBundleContext
.getBundles()) {
130 if (b
.getBundleId() == 0)
132 String location
= b
.getLocation();
133 if (location
.contains("/org.argeo.tp/") //
134 || location
.contains("/org.argeo.tp.sys/") //
135 || location
.contains("/org.argeo.tp.httpd/") //
136 || location
.contains("/org.argeo.tp.sshd/") //
138 framework
.getBundleContext().installBundle(b
.getLocation());
142 OsgiBoot osgiBoot
= new OsgiBoot(framework
.getBundleContext());
144 // OsgiBoot.uninstallBundles(osgiBoot.getBundleContext(), "org.argeo.api.cms");
145 // OsgiBoot.uninstallBundles(osgiBoot.getBundleContext(), "org.osgi.service.useradmin");
146 // osgiBoot.getBundleContext()
147 // .installBundle("initial@reference:file:../../../../../argeo-commons/org.argeo.api.cms/");
148 // osgiBoot.getBundleContext().installBundle(
149 // "reference:file:/usr/local/share/a2/osgi/equinox/org.argeo.tp.osgi/org.osgi.service.useradmin.1.1.jar");
152 osgiBoot
.startBundles();
154 // for (Bundle b : framework.getBundleContext().getBundles()) {
155 // BundleContext bc = b.getBundleContext();
157 // System.err.println(b.getSymbolicName() + " BC null");
160 UUID frameworkUuid
= UUID
.fromString(framework
.getBundleContext().getProperty(Constants
.FRAMEWORK_UUID
));
161 subFrameworks
.put(frameworkUuid
, framework
);
162 logger
.log(INFO
, "Created subframework " + frameworkUuid
+ " in parent " + foreignFrameworkUuid
);
164 } catch (Exception e
) {
165 throw new IllegalStateException("Cannot start framework", e
);
170 public void stop(BundleContext context
) throws Exception
{
171 for (Iterator
<Framework
> it
= subFrameworks
.values().iterator(); it
.hasNext();) {
172 Framework framework
= it
.next();
177 // for (Framework framework : subFrameworks.values()) {
180 subFrameworks
.clear();
181 foreignBundleContext
= null;
182 frameworkFactory
= null;
185 static class ParentBundleModuleConnector
implements ModuleConnector
{
186 private final BundleContext foreignBundleContext
;
187 private BundleContext localBundleContext
;
189 public ParentBundleModuleConnector(BundleContext foreignBundleContext
) {
190 this.foreignBundleContext
= foreignBundleContext
;
194 public Optional
<BundleActivator
> newBundleActivator() {
195 return Optional
.of(new BundleActivator() {
197 public void start(BundleContext context
) throws Exception
{
198 ParentBundleModuleConnector
.this.localBundleContext
= context
;
202 public void stop(BundleContext context
) throws Exception
{
203 ParentBundleModuleConnector
.this.localBundleContext
= null;
210 public void initialize(File storage
, Map
<String
, String
> configuration
) {
214 public Optional
<ConnectModule
> connect(String location
) throws BundleException
{
215 Bundle bundle
= foreignBundleContext
.getBundle(location
);
216 if (bundle
!= null && bundle
.getBundleId() != 0) {
217 // System.out.println("Foreign Bundle: " + bundle.getSymbolicName() + " " +
219 ConnectModule module
= new ConnectModule() {
222 public ConnectContent
getContent() throws IOException
{
223 return new ForeignBundleConnectContent(localBundleContext
, bundle
);
226 return Optional
.of(module
);
228 return Optional
.empty();
232 static class ForeignBundleClassLoader
extends ClassLoader
{// implements BundleReference {
233 private BundleContext localBundleContext
;
234 private Bundle foreignBundle
;
236 public ForeignBundleClassLoader(BundleContext localBundleContext
, Bundle foreignBundle
) {
237 super("Foreign bundle " + foreignBundle
.toString(), Optional
238 .ofNullable(foreignBundle
.adapt(BundleWiring
.class)).map((bw
) -> bw
.getClassLoader()).orElse(null));
239 this.localBundleContext
= localBundleContext
;
240 this.foreignBundle
= foreignBundle
;
244 protected Bundle
getBundle() {
245 return localBundleContext
.getBundle(foreignBundle
.getLocation());
249 // public URL getResource(String resName) {
250 // URL res = super.getResource(resName);
255 // protected URL findResource(String resName) {
256 // Bundle localBundle = getBundle();
257 // if (localBundle != null) {
258 // URL res = localBundle.getEntry(resName);
267 static class ForeignBundleConnectContent
implements ConnectContent
{
268 private final Bundle foreignBundle
;
269 private final ClassLoader classLoader
;
271 public ForeignBundleConnectContent(BundleContext localBundleContext
, Bundle foreignBundle
) {
272 this.foreignBundle
= foreignBundle
;
273 this.classLoader
= new ForeignBundleClassLoader(localBundleContext
, foreignBundle
);
277 public Optional
<Map
<String
, String
>> getHeaders() {
278 Dictionary
<String
, String
> dict
= foreignBundle
.getHeaders();
279 List
<String
> keys
= Collections
.list(dict
.keys());
280 Map
<String
, String
> dictCopy
= keys
.stream().collect(Collectors
.toMap(Function
.identity(), dict
::get
));
281 return Optional
.of(dictCopy
);
285 public Iterable
<String
> getEntries() throws IOException
{
286 List
<String
> lst
= Collections
.list(foreignBundle
.findEntries("", "*", true)).stream()
287 .map((u
) -> u
.getPath()).toList();
292 public Optional
<ConnectEntry
> getEntry(String path
) {
293 URL u
= foreignBundle
.getEntry(path
);
295 u
= foreignBundle
.getEntry("bin/" + path
);
296 // System.err.println(u2);
299 if ("plugin.xml".equals(path
))
300 return Optional
.empty();
301 if (path
.startsWith("META-INF/versions/"))
302 return Optional
.empty();
303 System
.err
.println(foreignBundle
.getSymbolicName() + " " + path
+ " not found");
304 return Optional
.empty();
307 ConnectEntry urlConnectEntry
= new ConnectEntry() {
310 public String
getName() {
315 public long getLastModified() {
316 return foreignBundle
.getLastModified();
320 public InputStream
getInputStream() throws IOException
{
321 return url
.openStream();
325 public long getContentLength() {
329 return Optional
.of(urlConnectEntry
);
333 public Optional
<ClassLoader
> getClassLoader() {
335 // cl = bundle.adapt(BundleWiring.class).getClassLoader();
337 // cl = subFrameworkClassLoader;
339 return Optional
.of(cl
);
340 // return Optional.empty();
344 public void open() throws IOException
{
348 public void close() throws IOException
{