[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ecf-dev] How to catch an Exception while registering a remote service?

Hi Scott,

Thanks for the quick reply. That makes perfect sense. I saw that you have already pushed a possible fix. I will verify this and report back in the bug.

Cheers,
Christoph

-----Ursprüngliche Nachricht-----
Von: ecf-dev-bounces@xxxxxxxxxxx [mailto:ecf-dev-bounces@xxxxxxxxxxx] Im Auftrag von Scott Lewis
Gesendet: Montag, 8. Februar 2016 00:30
An: ecf-dev@xxxxxxxxxxx
Betreff: Re: [ecf-dev] How to catch an Exception while registering a remote service?

On 2/7/2016 12:18 PM, Keimel, Christoph wrote:
> Hi Scott,
>
> thanks for all the helpful information! I started with possibility #1: implement a  RemoteServiceAdminListener since this would not only catch the error I am having right now, but also others I haven't encountered yet. And it seems to be the fastest way to attack the issue.
>
> I did notice however that in my case RemoteServiceAdminListener#remoteAdminEvent is never called because RemoteServiceAdmin#exportService is terminated at Line 324 with an IllegalArgumentException.
> I would have expected an "error registration" to be added to the result list instead of throwing the exception.

According to the spec and the CT, there are some exceptions that are handled with an error registration, and others that should result in an
IllegalArgumentException.   As I recall this wasn't what some of us
wanted to do WRT failure cases (I think it would make more sense to always to the same thing in failure cases).

> There is a link to a Bug discussion in the code [1] which I don't have access to, so I can't see what was discussed there. Is this intentional or is this a bug?

I believe it's intentional...because of the spec and the CT behavior.
The bug at [1] was associated with a CT test case I believe...having to do with the way that a compliant implementation should fail that specific CT test in order to pass the CT.

Unfortunately, I can't access that bug myself right now so I'm operating a bit on memory.

As I recall, the spec says something like:   If the specified export
config (specified via service.exported.config service property) does not exist/is not present then an IllegalArgumentException should be thrown,
and so if a container cannot be found/selected this is done.   However,
in your case it can be found/selected, but it cannot be
created/configured because of a port conflict.    So this case is
somewhat ambiguous.

I can/will check the specification and find out if I can separate these two failure cases (found/selected vs. created/configured) and if I can according to the spec, I will modify the behavior of RSA to throw IllegalArgumentException for not found/selected, and to creat/complete
an error registration for failure to create/configure.   I believe I can
implement this fairly quickly. Seem reasonable?    It would be possible
for you to use method 2 or 3 as I described, but it's probably better that this get addressed in a better/more usable way (i.e. so that method
1 will work).

I've created a bug to track this:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=487419

This seems to me like a better path to go on than to explain how you could do what you want to do in a more convoluted way (e.g. register a
framework listener and respond to these framework events).   Let me
know...Christoph if you disagree I could explain setting up a FrameworkListener but I would rather just modify RSA to do what's expected.

Scott

>
> Cheers,
> Christoph
>
> [1]: https://www.osgi.org/members/bugzilla/show_bug.cgi?id=2591
>
>
>
> -----Ursprüngliche Nachricht-----
> Von: ecf-dev-bounces@xxxxxxxxxxx [mailto:ecf-dev-bounces@xxxxxxxxxxx]
> Im Auftrag von Scott Lewis
> Gesendet: Samstag, 6. Februar 2016 22:46
> An: ecf-dev@xxxxxxxxxxx
> Betreff: Re: [ecf-dev] How to catch an Exception while registering a remote service?
>
> Hi Christoph,
>
> On 2/6/2016 6:35 AM, Keimel, Christoph wrote:
>> Hi Everybody,
>>
>> Thanks Wim und Scott for the input on my earlier questions regarding network failures. That helped a lot!
>>
>> Today I am trying to tackle something else that sometimes happens during startup: A service is not correctly registered as a remote service because the address used for the binding is already in use (stack trace see [1]). This happens on site from time to time and I would like to show an error message if it does but I don't know how to catch this event.
>>
>> I register the service with:
>>      ServiceRegistration<?> registration =
>> bundleContext.registerService(clazz, service, props); This leads to an exception being logged, but I can't catch it. Actually it looks to me like the returned registration is valid, and it probably is locally.
> Yes the registration returned is valid locally.
>
>> Is there a setting I could use to have registerService fail if the remote registration fails?
> By RSA specification, there is not a pre-defined setting that would have the registerService fail if the remote registration fails. This could be added for ECF, but I'm sort of hesitant to do so (as it would be non-standard), given that there are approaches (discussed below) that can be used to deal with this situation.
>
>> Or some other way to detect this error? In my case, the service is only used remotely, so I would really like to know if it couldn't be registered for some reason.
> Yes, of course.   There are a couple of ways to deal with this
> technically.  First, just a little bit of explanation of the way that RSA behaves:
>
> In RSA there's a concept of a 'topology manager' [1].  On the remote
> service host, the topology manager has the role of
>
> a) intercepting the registerService call via the OSGi service hook
> b) making a decision about whether to export the service (e.g. based
> upon the service properties and/or other things),
> c) calling
> org.osgi.service.remoteserviceadmin.RemoteServiceAdmin.exportService(S
> erviceReference,
> Map) to export the service
>
> If you look at the RemoteServiceAdmin service exportService method signature [2], you will see that it returns an Collection<ExportRegistration>.  In this collection will be at least one instance of ExportRegistration, and in this export registration is access to a Throwable that was possibly thrown by the call to
> exportService (e.g. because the port was already taken).   If everything
> was exported successfully, the Throwable is null.
>
> ECF has a 'default' topology manager (called the BasicTopologyManager) that is present in this bundle:
> org.eclipse.ecf.osgi.services.distribution.   This topology manager is
> what's called 'promiscuous' because it automatically tries to export
> *all* appropriate calls to registerService (i.e. those that have the required remote service properties) *and* because it has no means to do so, it can't return the ExportRegistration returned from RemoteServiceAdmin.exportService, but rather it simply logs any export error.
>
> With the RSA concept of a topology manager, there are a few ways to get access to these export registrations and the underlying Throwable exception.
>
> 1) One way is to register an instance of org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener [3], and the when a export event occurs your listener will be called with the
> appropriate RemoteServiceAdminEvent.   You can then check whether or not
> the export succeeded by checking whether an Throwable was thrown, and then if it did occur then you can do something else after the
> registerService call returns.   Note that the RemoteServiceAdminListener
> will be called synchronously by the same thread that calls registerService and RSA.exportService.  Actually, all RemoteServiceAdminListeners will be called before RSA.exportService returns.
>
> 2) A second way would be to create your own topology manager and replace
> the BasicTopologyManager with your own.   Then you could add logic (by
> extending the BasicTopologyManager) to check the ExportRegistration returned by RSA.exportService, and if found you could throw a RuntimeException to halt the registerService call. Note you can do many other things by replacing the BasicTopologyManager.
>
> 3) A third way would be to simply remove the BasicTopologyManager, and call RemoteServiceAdmin.exportService *directly* in your own application
> code.     You could then get the ExportRegistration returned, check for
> any exceptions upon export and do whatever was desired/appropriate.
>
> I think that each of these would allow you to handle your exceptional
> cases.   They differ a little bit in how much control you have, but it
> does add a lot of flexibility over the remote service export and import and it's all within specification.
>
> Please let all know if this helps.
>
> Scott
>
> [1] http://wiki.eclipse.org/EIG:Remote_Services_Admin
> [2]
> http://download.eclipse.org/rt/ecf/latest/javadoc/org/osgi/service/rem
> oteserviceadmin/RemoteServiceAdmin.html
> [3]
> http://download.eclipse.org/rt/ecf/latest/javadoc/org/osgi/service/rem
> oteserviceadmin/RemoteServiceAdminListener.html
>
>> ECF Version 3.12.0.v20151130-0157
>> Distribution Provider: generic
>> Discovery provider: zeroconf
>>
>> In case you want to know why this can happen although everything is configured correctly, here is the explanation: An application using remote services is running and works ok. For some reason the user closes the application and restarts it right away. Unfortunately, after the window is gone the application takes some time (2-3 seconds) to actually shut down. If it is restarted to early, the data area is already free (otherwise equinox would already through an error) but the remote binding address is not. Since the error is only logged the restarted application window is shown, but the remote services are not available. From the users point of view it is currently impossible to detect this problem without looking into the log (which our default game operator won't do).
> Right, makes perfect sense.
>
> Scott
>
>
>> Thanks for your help!
>>
>> Cheers,
>> Christoph
>>
>> [1] Stacke Trace
>>
>> 15:12:50.963 ERROR o.e.ecf.osgi.services.distribution -
>> FrameworkEvent ERROR
>> org.osgi.framework.ServiceException: Exception in org.eclipse.ecf.internal.osgi.services.distribution.BasicTopologyManagerComponent.event()
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.notifyHookPrivileged(ServiceRegistry.java:1288) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.notifyHooksPrivileged(ServiceRegistry.java:1263) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.notifyEventListenerHooksPrivileged(ServiceRegistry.java:1235) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:841) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:127) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.registerService(ServiceRegistry.java:225) ~[na:na]
>>      at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:464) ~[na:na]
>>      at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:482) ~[na:na]
>>      at org.eclipse.osgi.internal.framework.BundleContextImpl.registerService(BundleContextImpl.java:998) ~[na:na]
>>      at de.kware.pi.core.component.RemoteServiceComponent.registerService(RemoteServiceComponent.java:105) ~[na:na]
>>      at de.kware.app.agent.bomb.internal.BombActivator.start(BombActivator.java:60) ~[na:na]
>>      ...
>> Caused by: java.lang.IllegalArgumentException: Failed to select, create, or configure ECF host container
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.exportService(RemoteServiceAdmin.java:324) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractTopologyManager.handleServiceRegistering(AbstractTopologyManager.java:442) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractTopologyManager.handleEvent(AbstractTopologyManager.java:404) ~[na:na]
>>      at org.eclipse.ecf.internal.osgi.services.distribution.BasicTopologyManagerImpl.event(BasicTopologyManagerImpl.java:119) ~[na:na]
>>      at org.eclipse.ecf.internal.osgi.services.distribution.BasicTopologyManagerComponent.event(BasicTopologyManagerComponent.java:57) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry$6.call(ServiceRegistry.java:1238) ~[na:na]
>>      at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.notifyHookPrivileged(ServiceRegistry.java:1280) ~[na:na]
>>      ... 42 common frames omitted
>> Caused by: org.eclipse.ecf.osgi.services.remoteserviceadmin.SelectContainerException: Exception creating or configuring container
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractContainerSelector.createContainer(AbstractContainerSelector.java:153) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractHostContainerSelector.createRSContainer(AbstractHostContainerSelector.java:333) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractHostContainerSelector.createMatchingContainer(AbstractHostContainerSelector.java:319) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractHostContainerSelector.createAndConfigureHostContainers(AbstractHostContainerSelector.java:244) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.HostContainerSelector.selectHostContainers(HostContainerSelector.java:77) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin$1.run(RemoteServiceAdmin.java:315) ~[na:na]
>>      at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_60]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.exportService(RemoteServiceAdmin.java:312) ~[na:na]
>>      ... 48 common frames omitted
>> Caused by: org.eclipse.ecf.core.ContainerCreateException: Create of containerType=ecf.generic.server failed.
>>      at org.eclipse.ecf.provider.generic.GenericContainerInstantiator.createInstance(GenericContainerInstantiator.java:303) ~[na:na]
>>      at org.eclipse.ecf.core.ContainerFactory.createContainer(ContainerFactory.java:296) ~[na:na]
>>      at org.eclipse.ecf.core.ContainerFactory.createContainer(ContainerFactory.java:592) ~[na:na]
>>      at org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractContainerSelector.createContainer(AbstractContainerSelector.java:147) ~[na:na]
>>      ... 55 common frames omitted
>> Caused by: java.net.BindException: Address already in use: JVM_Bind
>>      at java.net.TwoStacksPlainSocketImpl.socketBind(Native Method) ~[na:1.8.0_60]
>>      at java.net.TwoStacksPlainSocketImpl.socketBind(TwoStacksPlainSocketImpl.java:137) ~[na:1.8.0_60]
>>      at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387) ~[na:1.8.0_60]
>>      at java.net.TwoStacksPlainSocketImpl.bind(TwoStacksPlainSocketImpl.java:110) ~[na:1.8.0_60]
>>      at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:190) ~[na:1.8.0_60]
>>      at java.net.ServerSocket.bind(ServerSocket.java:375) ~[na:1.8.0_60]
>>      at java.net.ServerSocket.<init>(ServerSocket.java:237) ~[na:1.8.0_60]
>>      at org.eclipse.ecf.provider.comm.tcp.Server.<init>(Server.java:42) ~[na:na]
>>      at org.eclipse.ecf.provider.generic.TCPServerSOContainerGroup.putOnTheAir(TCPServerSOContainerGroup.java:71) ~[na:na]
>>      at org.eclipse.ecf.provider.generic.TCPServerSOContainer.<init>(TCPServerSOContainer.java:94) ~[na:na]
>>      at org.eclipse.ecf.provider.generic.GenericContainerInstantiator.createServerContainer(GenericContainerInstantiator.java:282) ~[na:na]
>>      at org.eclipse.ecf.provider.generic.GenericContainerInstantiator.createInstance(GenericContainerInstantiator.java:297) ~[na:na]
>>      ... 58 common frames omitted
>> _______________________________________________
>> 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

_______________________________________________
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