You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Tom Watson (Jira)" <ji...@apache.org> on 2020/06/03 19:04:00 UTC

[jira] [Commented] (FELIX-6284) Felix Connect Native-Image support

    [ https://issues.apache.org/jira/browse/FELIX-6284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17125236#comment-17125236 ] 

Tom Watson commented on FELIX-6284:
-----------------------------------

Atomos does support embedding bundle resources directly into the native image such that the duplicates get their own unique path (including META-INF/MANIFEST.MF).  All unique resources can be included in the root of the image.  Any duplicates are placed in a folder with an ID per bundle.  Additionally an index file is included that lists all the bundles that got compiled into the image.  This file is used by Atomos at runtime to discover the bundles and their entry paths.

https://github.com/apache/felix-atomos/tree/master/atomos.examples/atomos.examples.index 

An example that uses this approach to create an uber JAR that contains all the content from the bundles and indexes duplicates.  This is not a native-image example, but it shows the concept more easily than the native-image example:

https://github.com/apache/felix-atomos/tree/master/atomos.examples/atomos.examples.substrate.maven

> Felix Connect Native-Image support
> ----------------------------------
>
>                 Key: FELIX-6284
>                 URL: https://issues.apache.org/jira/browse/FELIX-6284
>             Project: Felix
>          Issue Type: Improvement
>          Components: Connect
>    Affects Versions: connect-0.2.0
>            Reporter: Pierre De Rop
>            Assignee: Pierre De Rop
>            Priority: Minor
>
> The upcoming OSGi R8 will allow to combine OSGi with application compiled with graalVM/native-image, and maybe Atomos already supports this. In the meantime, I need to use the old apache Felix Connect library in GraalVM substrate/native-image environment.
> To do so, there might be few adaptions to be done in Felix Connect. One is about how bundles are scanned by the *ClasspathScanner* class. Currently, this class provides a "scanForBundles" method which looks for all bundle URLS available from the classpath, using:
> {code:java}
> Enumeration<URL> ClassLoader.getResources("META-INF/MANIFEST.MF") {code}
> This works fine in classpath environment, and collected URLS (jar:file) are then used to create BundleDescriptors. Each BundleDescriptor can then get access to bundle content using the URL.
> The ClassLoader.getResource method returns for instance URLS like:
> {code:java}
> jar:file:/home/pderop/felix.connect/bundles/org.apache.felix.gogo.command-1.1.0.jar!/META-INF/MANIFEST.MF
> jar:file:/home/pderop/felix.connect/bundles/org.apache.felix.metatype-1.2.2.jar!/META-INF/MANIFEST.MF
> etc ...{code}
> But in compiled applications (using substrate/native image), the ClassLoader.getResources("META-INF/MANIFEST.MF") method returns an enumeration of URLS which are all the same (using "resource" protocol) for all found bundles. For example, for gogo and metatype bundles in the example above, the ClassLoader.getResources("META-INF/MANIFEST.MF") would return these same urls:
> {code:java}
> resource:META-INF/MANIFEST.MF
> resource:META-INF/MANIFEST.MF {code}
> this is problematic, because it's not possible to load resources from a bundle using a unique jar:file url. Moreover, in native-image, using the "resource" url seems to cause problems, and it seems we can only open and read "resource" input stream only one time.  I also observed some exceptions when reading "resource" inputstreams, like this:
> {code:java}
> DEBUG: bundle jaxrs.hello:0.0.0 (11)BundleComponentActivator : Descriptor locations OSGI-INF/sample.jaxrs.HelloDS.xml
> java.io.IOException: Stream closed
>         at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:165)
>         at java.io.BufferedInputStream.fill(BufferedInputStream.java:252)
>         at java.io.BufferedInputStream.read(BufferedInputStream.java:271)
>         at org.apache.felix.connect.URLRevision.getUrlContent(URLRevision.java:131)
>         at org.apache.felix.connect.URLRevision.getEntries(URLRevision.java:73)
>         at org.apache.felix.connect.EntryFilterEnumeration.<init>(EntryFilterEnumeration.java:52)
>         at org.apache.felix.connect.PojoSRBundle.findEntries(PojoSRBundle.java:486)
>         at org.apache.felix.scr.impl.BundleComponentActivator.findDescriptors(BundleComponentActivator.java:413)
>         at org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:313)
>         at org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:263)
>         at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:551)
>         at org.apache.felix.scr.impl.Activator.access$200(Activator.java:69)
>         at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:424)
>         at org.apache.felix.scr.impl.AbstractExtender.createExtension(AbstractExtender.java:196)
>         at org.apache.felix.scr.impl.AbstractExtender.modifiedBundle(AbstractExtender.java:169)
>         at org.apache.felix.scr.impl.AbstractExtender.modifiedBundle(AbstractExtender.java:49)
>         at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:488)
>         at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:420)
>         at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:232)
>         at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:450)
>         at org.apache.felix.connect.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:821)
>         at org.apache.felix.connect.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:771)
>         at org.apache.felix.connect.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:510)
>         at org.apache.felix.connect.PojoSRBundle.start(PojoSRBundle.java:157)
>         at org.apache.felix.connect.PojoSR.startBundles(PojoSR.java:286)
>         at com.nokia.as.service.felixconnect.impl.Launch.start(Launch.java:161)
>         at com.nokia.as.service.felixconnect.impl.Launch.main(Launch.java:76)
> {code}
> I don't know currently if there is an API in graalvm which could be used as a work around, but in the meantime, a method can be added in the ClasspathScanner in order to load original jars from a directory, using jar:file URL protocol. In this way, we can still use "jar:file" URLS as before. So, it means the original jars must be kept beside the executable. Maybe the patch can be improved later, but it's light and allows compiled applications to use declarative service, configadmin, dependency manager, etc ... I will create a PR for this.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)