[
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 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(ServiceReference,
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/remoteserviceadmin/RemoteServiceAdmin.html
[3]
http://download.eclipse.org/rt/ecf/latest/javadoc/org/osgi/service/remoteserviceadmin/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