[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ecf-dev] Failed to inject method in E4

Hi Scott,

Thank you for looking into this. It made me realize what is going on. I think we have found a special DI case where the provider and the receiver of the service both don't know its class.

With E4, the following construct is possible:

class MyView {
 @Inject @Optional
 IRunControllerService service
}

If an instance of the specific service is found by the DI framework, it is placed in the "context" (DI goodybag hashmap,) From this context the requesting classes are visited and the service is injected into MyView.

In the above annotation you tell the Eclipse DI framework to inject the instance of the service into instances of MyView if the service changes in the context.

So this is what happens.

1. The above MyView instance is created by the DI framework (it is a view or an editor or something).
2. The DI fw sees that MyView is looking for the IRCS service and starts tracking for this service
3. At some point ECF creates a proxy for this service
4. ECF sees that the service is to be deliverd to the DI fw and uses its classloader to instantiate the object.
5. The IRCS is not in the dependencies of the DI framework so the class cannot be found

It is an interesting problem and I wonder how it could be solved. The problem is the way ECF is trying to load the class as you explained. If it failes to load the class at this point it should fall back to some alternative methods of loading the class.

There are two solutions that spring to mind:

1. When the class cannot be loaded, ECF looks inside OSGi to fiind who is _importing_ the package of this class and use that bundle to load the class.
2. Let the consumer register a special factory that can provide instances of this class

I have filed https://bugs.eclipse.org/bugs/show_bug.cgi?id=442764


Workaround
In order to solve this they have found the following workaround.

Make a new interface ILocalRemoteControllerService extends IControllerService
1. Let MyView use ILRCS for its DI
2. Track IRCS yourself
3. Wrap it in an ILRCS instance
4. Put ILRCS in the context
5. Let DI give it to MyView

Cheers,

Wim



On Wed, Aug 27, 2014 at 11:49 PM, Scott Lewis <slewis@xxxxxxxxxxxxx> wrote:
Hi Guys,

Hmm.ÂÂ I've looked over the output below, and this doesn't immediately appear to me to be some problem with ECF's remote services.ÂÂ I can't really tell, however, whether it's some issue with the e4 dependency injection system.ÂÂ That appears the likely explanation, but I really don't know or understand the e4 mechanisms very well.ÂÂ

But let me tell you what appears to be going on with the exception below, and perhaps those that know more about e4 can use this info.

When ECF discovers and then imports a remote service, the first thing it needs to do to create a proxy for that service is to load the service interface class (represented by RemoteServiceAdmin.loadServiceInterfacesViaBundle on stack below). To load the service interface, it can't use the RSA bundle to do so (i.e. Bundle.loadClass), but rather it has to use the bundle that's requesting access to the OSGi service. In the case of the below the service type is IRunControllerService, and the requesting bundle is org.eclipse.e4.ui.workbench.ÂÂ

The reason this is necessary has to do with OSGi's rules about exports and imports. Obviously the RSA code knows nothing about IRunControllerService, and so typically the only Bundle that does is the one that is asking for the service (because it has to cast it to the service type anyway...just to use it...and so has to import the service type). This is also related to OSGi's service-level security, as only bundles that declare their imports (and have appropriate service permissions if running with security manager), can load the service type class. One way to summarize this is that this behavior is not an ECF RSA implementation choice, but rather more a required/specified behavior for proxy classloading since it has to be able to load the service type classes in order to create the proxy.

Anyway, what seems to be happening in this case is that it's the e4.ui.workbench that's requesting access to the proxy, and so RSA is using the e4.ui.workbench bundle to attempt to load the service type class. Â It makes sense that the e4.ui.workbench bundle wouldn't know about this service, but what I don't understand is why is it trying to request/get the service...without access to the service type? Â That's where I don't know enough about the e4 di stuff and where I run out of answers.

It certainly must work with ServiceTracker and/or DS. Â I'm not precisely sure how DS manages this but obviously it does as part of compliance with the DS specification.ÂÂ My guess is that it's the DS injectee bundle that gets used as the requester/getter of any service, rather than the ds implementation bundle, but I'm not certain of that.

Scott



On 8/27/2014 12:42 PM, J Langley wrote:
Incredible timing!

I ran into the exact same issue yesterday. ÂI have services on a remote machine that I can connect to client services using DS, but if I try to @Inject them into a GUI element I get the error that Wim mentioned. ÂI haven't had enough time to track down the root cause yet, but I reply with anything I find. ÂI considered creating a bug, but I would like to see if it is an issue with ECF or an underlying E4 problem.

In the meantime, I think I will create an Addon that uses a service tracker to find the service and add it to the context.

Thanks,
-J.


From: "Wim Jongman" <wim.jongman@xxxxxxxxx>
To: "Eclipse Communication Framework (ECF) developer mailing list." <ecf-dev@xxxxxxxxxxx>
Sent: Wednesday, August 27, 2014 1:45:49 PM
Subject: [ecf-dev] Failed to inject method in E4

Hi,


I have advised ECF on a project creating an E4 based RCP application and we have found and odd thing. When a service is discovered and published in the local OSGi containter there is an exception when E4 dependency injection wants to instantiate the object.

When the service is obtained with a service tracker and then pushed into the e4 context everything is ok.

We get a CNFE like this:

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";

I appreciate your ideas.

Cheers,

Wim


osgi> !SESSION 2014-08-27 14:38:16.217 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.7.0_60
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
Framework arguments:Â -product ln.ont.sdaorj.gui.product -clearPersistedState
Command-line arguments:Â -product ln.ont.sdaorj.gui.product -data O:\/../runtime-ln.ont.sdaorj.client.product -dev file:O:/.metadata/.plugins/org.eclipse.pde.core/ln.ont.sdaorj.client.product/dev.properties -os win32 -ws win32 -arch x86 -consoleLog -clearPersistedState -console

!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@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[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)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$ProxyServiceFactory.getService(RemoteServiceAdmin.java:1670)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse$1.run(ServiceFactoryUse.java:212)
ÂÂÂ at java.security.AccessController.doPrivileged(Native Method)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.factoryGetService(ServiceFactoryUse.java:210)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.getService(ServiceFactoryUse.java:111)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceConsumer$2.getService(ServiceConsumer.java:45)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.getService(ServiceRegistrationImpl.java:489)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.getService(ServiceRegistry.java:461)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.getService(BundleContextImpl.java:619)
ÂÂÂ at org.eclipse.e4.core.internal.contexts.osgi.EclipseContextOSGi.serviceChanged(EclipseContextOSGi.java:120)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:109)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:914)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:862)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:127)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:225)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:464)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$10.run(RemoteServiceAdmin.java:1569)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$10.run(RemoteServiceAdmin.java:1)
ÂÂÂ at java.security.AccessController.doPrivileged(Native Method)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.createAndRegisterProxy(RemoteServiceAdmin.java:1567)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.importService(RemoteServiceAdmin.java:2134)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.importService(RemoteServiceAdmin.java:423)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractTopologyManager.handleECFEndpointAdded(AbstractTopologyManager.java:244)
ÂÂÂ at org.eclipse.ecf.internal.osgi.services.distribution.BasicTopologyManagerImpl.endpointAdded(BasicTopologyManagerImpl.java:123)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescriptionLocator$1.dispatchEvent(EndpointDescriptionLocator.java:156)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:340)
DEBUG - StartScenarioHandler - Run controller service registered @ StartScenarioHandler
DEBUG - AsFastAsPossibleHandler - Run controller service registered @ AsFastAsPossibleHandler
DEBUG - PauseScenarioHandler - Run controller service registered @ PauseScenarioHandler
DEBUG - StopScenarioHandler - Run controller service registered @ StopScenarioHandler
DEBUG - ScenarioTimeVisualizer - Run controller service registered @ ScenarioTimeVisualizer

!ENTRY org.eclipse.ecf.osgi.services.remoteserviceadmin.proxyDEBUG - ScenarioSpeedSlider - Run controller service registered @ ScenarioSpeedSlider
Â4 0 2014-08-27 14:38:39.752
!MESSAGE FrameworkEvent ERROR
!STACK 0
org.osgi.framework.ServiceException: Exception in org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$ProxyServiceFactory.getService()
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.factoryGetService(ServiceFactoryUse.java:222)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.getService(ServiceFactoryUse.java:111)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceConsumer$2.getService(ServiceConsumer.java:45)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.getService(ServiceRegistrationImpl.java:489)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.getService(ServiceRegistry.java:461)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.getService(BundleContextImpl.java:619)
ÂÂÂ at org.eclipse.e4.core.internal.contexts.osgi.EclipseContextOSGi.serviceChanged(EclipseContextOSGi.java:120)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:109)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:914)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:862)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:127)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:225)
ÂÂÂ at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:464)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$10.run(RemoteServiceAdmin.java:1569)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$10.run(RemoteServiceAdmin.java:1)
ÂÂÂ at java.security.AccessController.doPrivileged(Native Method)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.createAndRegisterProxy(RemoteServiceAdmin.java:1567)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.importService(RemoteServiceAdmin.java:2134)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.importService(RemoteServiceAdmin.java:423)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractTopologyManager.handleECFEndpointAdded(AbstractTopologyManager.java:244)
ÂÂÂ at org.eclipse.ecf.internal.osgi.services.distribution.BasicTopologyManagerImpl.endpointAdded(BasicTopologyManagerImpl.java:123)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescriptionLocator$1.dispatchEvent(EndpointDescriptionLocator.java:156)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
ÂÂÂ at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:340)
Caused by: java.lang.RuntimeException: ProxyServiceFactory cannot load any serviceInterfaces=[] for serviceReference={ln.ont.sdaorj.services.simulation.IRunControllerService}={endpoint.service.id=208, HOST_NAME=Name, service.scope=bundle, HOST_PORT=3787, service.bundleid=7, endpoint.id=5f790ac2-681b-4fe6-9fd8-b9359e2b70dd, service.imported=org.eclipse.ecf.provider.remoteservice.generic.RemoteServiceImpl@c7ed08, service.imported.configs=[ecf.generic.client], HOST_IP=192.168.192.85, service.id=211} via clientBundle=org.eclipse.e4.ui.workbench
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.createProxy(RemoteServiceAdmin.java:1700)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.access$5(RemoteServiceAdmin.java:1685)
ÂÂÂ at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$ProxyServiceFactory.getService(RemoteServiceAdmin.java:1670)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse$1.run(ServiceFactoryUse.java:212)
ÂÂÂ at java.security.AccessController.doPrivileged(Native Method)
ÂÂÂ at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.factoryGetService(ServiceFactoryUse.java:210)
ÂÂÂ ... 26 more
INFO - Class - Service ln.ont.sdaorj.services.simulation.IRunControllerService.proxy@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[containerID=StringID[ecftcp://192.168.192.85:3787/server];containerRelativeID=2] from Name arrived at remote broker
INFO - Class - Service ln.ont.sdaorj.services.simulation.IPlatformDataService$IExtendedPlatformDataService.proxy@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[containerID=StringID[ecftcp://192.168.192.85:3787/server];containerRelativeID=3] from Name arrived at remote broker
INFO - Class - Service ln.ont.sdaorj.services.simulation.ISystemTrackDataService$IExtendedSystemTrackDataService.proxy@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[containerID=StringID[ecftcp://192.168.192.85:3787/server];containerRelativeID=4] from Name arrived at remote broker
INFO - Class - Service ln.ont.sdaorj.services.simulation.IEngagementDataService$IExtendedEngagementDataService.proxy@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[containerID=StringID[ecftcp://192.168.192.85:3787/server];containerRelativeID=5] from Name arrived at remote broker

osgi> ss sdaorj
"Framework is launched."


idÂÂÂ StateÂÂÂÂÂÂ Bundle
4ÂÂÂ ACTIVEÂÂÂÂÂ ln.ont.sdaorj.gui_1.0.0.qualifier
12ÂÂÂ ACTIVEÂÂÂÂÂ ln.ont.sdaorj.scenario.runcontroller_1.0.0.qualifier
30ÂÂÂ ACTIVEÂÂÂÂÂ ln.ont.sdaorj.remotebroker_3.0.0.qualifier
33ÂÂÂ RESOLVEDÂÂÂ ln.ont.sdaorj.libraries_1.0.0
46ÂÂÂ STARTINGÂÂÂ ln.ont.sdaorj.messaging_4.0.0.qualifier
47ÂÂÂ RESOLVEDÂÂÂ ln.ont.sdaorj.services_1.0.0.qualifier
58ÂÂÂ RESOLVEDÂÂÂ ln.ont.sdaorj.common_1.0.0.qualifier
76ÂÂÂ RESOLVEDÂÂÂ ln.ont.sdaorj.data_1.0.0.qualifier
84ÂÂÂ ACTIVEÂÂÂÂÂ ln.ont.sdaorj.connection.controls_1.0.0.qualifier
osgi>



_______________________________________________
ecf-dev mailing list
ecf-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/ecf-dev



_______________________________________________
ecf-dev mailing list
ecf-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/ecf-dev



_______________________________________________
ecf-dev mailing list
ecf-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/ecf-dev