Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 442811

Summary: [DI] CNFE when OSGi service is injected
Product: [Eclipse Project] Platform Reporter: Wim Jongman <wim.jongman>
Component: RuntimeAssignee: platform-runtime-inbox <platform-runtime-inbox>
Status: CLOSED WORKSFORME QA Contact:
Severity: normal    
Priority: P3 CC: dirk.fauth, mario.curcija, patrick, psuzzi, slewis
Version: 4.5Keywords: helpwanted
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard:

Description Wim Jongman CLA 2014-08-28 11:25:45 EDT
Hi,

I have a DI use case that affects the proper working of the OSGi RSA (Remote Service Admin) specification inside Eclipse E4 [1].

A service implementing interface XYZ is consumed by an E4 application through DI like this:

class foo{
 @inject @optional
   XYZ service;
}

A remote service is received in the E4 application and the RSE spec implementer (ECF) must load this class. This is done through the bundle that tracks this service because this bundle knows about this class. This is discussed in chapter 122.5.6 in [1]

In the case of DI, it is tracking OSGi services with the org.eclipse.e4.ui.workbench bundle. ECF sees this and tries to load the XYZ class through this bundle. This fails with a CNFE.

Instead, DI should track the service with the bundle of the requesting object. This ensures proxies of any kind to properly load a class.

[1] http://www.osgi.org/download/r4v42/r4.enterprise.pdf
Comment 1 Wim Jongman CLA 2014-08-28 11:26:52 EDT
*** Bug 442764 has been marked as a duplicate of this bug. ***
Comment 2 Wim Jongman CLA 2014-08-28 11:29:20 EDT
!ENTRY org.eclipse.e4.ui.workbench 1 0 2014-08-27 14:38:17.122
!MESSAGE LifeCycleManager - Eclipse context registered @lifecyclemanager
INFO - RemoteBroker - Remote Broker constructed
INFO - RemoteBroker - Remote broker: service trackers active
INFO - HostConfigurationManager - Creating host configuration manager
INFO - Class - Service ln.ont.sdaorj.services.IHostConnectionService.proxy@org.eclipse.ecf.remoteservice.RemoteServiceID[containerID=StringID[ecftcp://192.168.192.85:3787/server];containerRelativeID=1] from Name arrived at remote broker

!ENTRY org.eclipse.ecf.osgi.services.remoteserviceadmin 4 0 2014-08-27 14:38:39.746
!MESSAGE org.eclipse.core.runtime.Status[plugin=org.eclipse.ecf.osgi.services.remoteserviceadmin;code=4;message=org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin:loadInterfacesViaBundle:interface=ln.ont.sdaorj.services.simulation.IRunControllerService cannot be loaded by clientBundle=org.eclipse.e4.ui.workbench;severity4;exception=java.lang.ClassNotFoundException: ln.ont.sdaorj.services.simulation.IRunControllerService cannot be found by osgi.identity; osgi.identity="org.eclipse.e4.ui.workbench"; type="osgi.bundle"; version:Version="1.1.0.v20140228-1539"; singleton:="true";children=[]]
!STACK 0
java.lang.ClassNotFoundException: ln.ont.sdaorj.services.simulation.IRunControllerService cannot be found by osgi.identity; osgi.identity="org.eclipse.e4.ui.workbench"; type="osgi.bundle"; version:Version="1.1.0.v20140228-1539"; singleton:="true"
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:416)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:336)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:328)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.loadClass(EquinoxBundle.java:568)
    at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.loadServiceInterfacesViaBundle(RemoteServiceAdmin.java:1635)
    at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.createProxy(RemoteServiceAdmin.java:1694)
    at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.access$5(RemoteServiceAdmin.java:1685)
Comment 3 Patrick Paulin CLA 2020-05-25 15:23:57 EDT
I've been struggling with this lately, and I'd really like to be able to use e4 DI with JAX-RS remote services. 

I've looked into the suggested solution on the duplicate bug entry, which is for the e4 OSGi context manager (EclipseContextOSGi) to use the originating bundle context to create the requested service. But it seems this would require significant changes to the EclipseContext API.

I'm wondering if anyone has got this working in other ways (an e4 AddOn, etc.).

One solution I've found is to add "DynamicImport-Package: *" to the manifest for the org.eclipse.e4.ui.workbench bundle. I'm not sure if this would be an option, I know it's considered something of a hack. But other framework bundles include this header to make class-loading more flexible, including Remote Services Admin.
Comment 4 Dirk Fauth CLA 2020-05-25 15:37:58 EDT
IIRC you want to use e4 injection to get an OSGi service, correct? Then you should use the @Service annotation with @Inject. Maybe there the classloading is done correctly.
Comment 5 Patrick Paulin CLA 2020-05-25 16:52:33 EDT
(In reply to Dirk Fauth from comment #4)
> IIRC you want to use e4 injection to get an OSGi service, correct? Then you
> should use the @Service annotation with @Inject. Maybe there the
> classloading is done correctly.

Yes, that does fix the class loading! The annotation bypasses the EclipseContextOSGi logic and loads the service using the consuming bundle's context.

I would say this bug can be closed. The injection works when:

1. @Service annotation is used in addition to @Inject
2. Bundle-ActivationPolicy: lazy is set on the bundle using the injected service
Comment 6 Scott Lewis CLA 2020-05-25 19:06:32 EDT
(In reply to Patrick Paulin from comment #5)
> (In reply to Dirk Fauth from comment #4)
> > IIRC you want to use e4 injection to get an OSGi service, correct? Then you
> > should use the @Service annotation with @Inject. Maybe there the
> > classloading is done correctly.
> 
> Yes, that does fix the class loading! The annotation bypasses the
> EclipseContextOSGi logic and loads the service using the consuming bundle's
> context.

FWIW:  RSA does the same thing...i.e. loads the service class + all referenced classes via the consuming bundle's context.   The distribution provider uses the OSGi wiring API to do so in a version-correct way.  Then RSA + distribution provider creates the instance and dynamically puts in the OSGi service registry...as RSA spec defines.

I don't happen to know how the @Inject + @Service handle dynamics (e.g. remote service proxy going away...or not being available at startup, etc).
Comment 7 Dirk Fauth CLA 2020-05-25 23:58:32 EDT
(In reply to Scott Lewis from comment #6)
> (In reply to Patrick Paulin from comment #5)
> > (In reply to Dirk Fauth from comment #4)
> > > IIRC you want to use e4 injection to get an OSGi service, correct? Then you
> > > should use the @Service annotation with @Inject. Maybe there the
> > > classloading is done correctly.
> > 
> > Yes, that does fix the class loading! The annotation bypasses the
> > EclipseContextOSGi logic and loads the service using the consuming bundle's
> > context.
> 
> FWIW:  RSA does the same thing...i.e. loads the service class + all
> referenced classes via the consuming bundle's context.   The distribution
> provider uses the OSGi wiring API to do so in a version-correct way.  Then
> RSA + distribution provider creates the instance and dynamically puts in the
> OSGi service registry...as RSA spec defines.
> 
> I don't happen to know how the @Inject + @Service handle dynamics (e.g.
> remote service proxy going away...or not being available at startup, etc).

IIRC it supports the same mechanics like DS. But you need to use @Optional additionally so the reinjection works if a service goes away. 

As an alternative I often use some wrapper service that is always available for injection in E4. And that service uses @Reference for consuming the remote service. This way the OSGi dynamics are fully supported while the E4 injection works with an always available service.
Comment 8 Wim Jongman CLA 2020-09-01 04:43:08 EDT
Thanks!