[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ecf-dev] Using a container multiple times

Hi Robert,

On 11/4/2010 9:18 AM, Robert Onslow wrote:
Dear All

On the server side, I have create a container and registered a shared
object on it.

I would like to publish a remote service over it as well. I tried:

final IContainer container =
manager.getContainerFactory().createContainer("ecf.generic.server");
final ISharedObjectContainer sharedObjectContainer =
(ISharedObjectContainer)
container.getAdapter(ISharedObjectContainer.class)
ISharedObjectManager manager1 = sharedObjectContainer.getSharedObjectManager();
Properties props = new Properties();
props.put(EventConstants.EVENT_TOPIC, "uk_co_xlegal_xbundle3_remote");
manager1.addSharedObject(IDFactory.getDefault().createStringID("uk.co.xlegal.xbundle3.remote"),
(ISharedObject) admin, props);

//now share the StateProvider service

IRemoteServiceContainerAdapter rsc = (IRemoteServiceContainerAdapter)
((IAdaptable) container).getAdapter(IRemoteServiceContainerAdapter.class);
StateProvider provider = (StateProvider) localStateServiceTracker.getService();
					

rsc.registerRemoteService(new String[]{StateProvider.class.getName()},
provider, null);

...

I am not seeing the service on the client side. I have connected, and
am successfully synchronizing the EventAdmin.
But if I register a tracker for the remote service, the remote service
is never found.

remoteStateProviderTracker = new ServiceTracker(context,
StateProvider.class.getName(), new ServiceTrackerCustomizer() {

			@Override
			public Object addingService(ServiceReference reference) {
//never reaching here

				StateProvider provider = (StateProvider) context.getService(reference);
				Map<String, Object>  state = provider.provideState();
				List<String>  openBundleURIs = (List<String>) state.get("openBundleURIs");
				
				for (String uri : openBundleURIs)
					syncWithBundleURI(uri);
				return provider;
			

			}

			@Override
			public void modifiedService(ServiceReference reference,
					Object service) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void removedService(ServiceReference reference,
					Object service) {
				
			}
			
		});

remoteStateProviderTracker.open();
							
Is it possible to use a server container in this way?


The short answer to your question is 'yes'.

But I'll give a slightly longer answer...and of course answer any follow up questions as needed.

One thing I should briefly explain about remote services...the ECF remote services API pre-dated the OSGi 4.2 remote services spec implementation. In fact, the OSGi remote services implementation actually *uses* the ECF remote services API to expose OSGi services remotely. One implication of this layering (which is described graphically here [1]), is that it's possible to use ECF remote services *without* the OSGi 4.2 remote services implementation.

So on your service host/server side, when you call

rsc.registerRemoteService(new String[]{StateProvider.class.getName()},
provider, null);

this makes the StateProvider service available to the ECF remote service API on the client side...but *not* the OSGi service registry. So, on the client, you could call something like this

IRemoteServiceReference[] refs = rsc.getRemoteServiceReferences(StateProvider.class.getName(),null);

Note that there is also a RemoteServiceTracker class (org.eclipse.ecf.remoteservice.util.tracker.RemoteServiceTracker). Instances of RemoteServiceTracker have the same general behavior as OSGi ServiceTrackers, but are based upon the ECF remote service API (rather than the OSGi service registry).

With the code above, I believe that's why your ServiceTracker doesn't discover the service...because the OSGi ServiceTracker only tracks service that are in the OSGi service registry. And you are registering the remote service via rsc.registerRemoteService (the ECF remote service API directly).

The ECF implementation of the OSGi 4.2 remote services specification, however, makes *any* direct use of the ECF remote services API unnecessary. That is, on the host/server-side, as per the OSGI spec, when an OSGi registration like this is done:

props.put("service.exported.configs","ecf.generic.server");
props.put("service.exported.interfaces","*");
ServiceRegistration reg = bundleContext.registerService(StateProvider.class.getName(),service, props);


the ECF impl of OSGi remote services intercepts this call..and ends up calling the ECF registerRemoteService method *for you* (as well as publishing the meta-data about the remote service via some discovery).

Then on the client/proxy side, the ECF implementation of OSGi 4.2 remote services uses the discovery to asynchronously discover the remote service meta-data, and then it turns around and calls the ECF getRemoteServiceReferences method for you, creates a proxy, and registers this proxy in the OSGi service registry...thus triggering detection by ServiceTrackers that are responding to the given service. Just for reference, the ECF impl of OSGi 4.2 remote services is in the bundles: org.eclipse.ecf.osgi.services.discovery and org.eclipse.ecf.osgi.services.distribution.

So in short, you can use the ECF remote services API directly, by using registerRemoteService (as you are doing on the host above), and getRemoteServiceReferences/RemoteServiceTracker on the client, or you can use the ECF impl of the OSGi 4.2 remote services specification (i.e. in the bundles given above)...along with some discovery, and use BundleContext.registerService (host), and getServiceReferences/ServiceTracker/DS on the client. Both mechanisms are available...and things are layered as shown in this diagram [1].

Scott

[1] http://wiki.eclipse.org/OSGi_4.2_Remote_Services_and_ECF