Monday, July 23, 2007

Remote OSGI over XMPP

In a previous post, I showed how real-time collaboration could be added to Eclipse/RCP apps using ECF datashare API running on the ECF XMPP provider.

One can also use ECF to make remote OSGi calls using the ECF remoteservices API.

For example, on an ECF XMPP peer that is to be the 'server' for a given service (a trivial IConcatService in this case):

// Get ECF adapter for remote services
IRemoteServiceContainerAdapter adapter = ... (e.g. from contacts list)
// Get targetID[] buddies who are to receive service registration
ID [] targetIDs = ... (e.g. from contacts list)
Dictionary props = new Hashtable();
props.put(Constants.SERVICE_REGISTRATION_TARGETS,targetIDs);
// Create service instance...this does the actual concatenate
Object concatService = new IConcatService() {
public String concat(String string1, String string2) {
return string1.concat(string2);
}
};
// Register service instance
adapter.registerRemoteService(new String[] { "IConcatService" }, concatService, props);
// Service now registered

And for clients to lookup and use the service:

// Get adapter for accessing remote services
IRemoteServiceContainerAdapter adapter = ...
// Get remote service reference
IRemoteServiceReference[] refs = adapter.getRemoteServiceReferences(null, "IConcatService", null);
// Get service for remote reference
IRemoteService service = adapter.getRemoteService(refs[0]);
// Create remote call
IRemoteCall remoteCall = new IRemoteCall() {
public String getMethod() {
return "concat";
}
public Object[] getParameters() {
return new Object[] { "Eclipse", " is cool" };
}

public long getTimeout() {
return 3000;
}};
// Call synchronously
String result = (String) service.callSynch(remoteCall);
System.out.println("concat result is: "+result);
// prints out: concat result is: Eclipse is cool

Further, note that the client can use any of the 'style's of remote invocation desired:

IRemoteService.callSynch(...)
IRemoteService.callAsynch(...)
IRemoteService.fireAsynch(...)
IRemoteService.getProxy()

With 'getProxy()' this returns an instance that implements IConcatService, and allows direct method invocation:

IConcatService concat = (IConcatService) remoteService.getProxy();
String result = concat.concat("OSGi"," is cool");
System.out.println("concat result is: "+result);
// prints out: concat result is: OSGi is cool

There is more test and example code available here. Note that with the IRemoteService.callAsynch, callSynch, and fireAsynch methods it is not even necessary that the client have the service interface locally. All that is needed is the string identifying the desired class name.

The support for remote services on the ECF generic provider is already in ECF 1.0.0, and the support for doing remote services on XMPP will be available in ECF 1.0.2.

11 comments:

bstarchev said...

I want to use test and example code available hire: http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.ecf/tests/org.eclipse.ecf.tests.remoteservice/?root=Technology_Project
But what have to enter about
Host:
User:
Password:
Boris Starchev - Teacher

Scott Lewis said...

Hi bstarchev,

Yes, you need to provide information for two xmpp accounts (one that publishes/registers the service, the other that uses the service). The way this is done for the test code in org.eclipse.ecf.tests.remoteservice.presence.RemoteServiceContainerAdapterTest package is to put the following (e.g. ) on the command line for the test:

-Dusername0=slewis@ecf.eclipse.org -Dpassword0=slewispassword
-Dusername1=fliwatuet@ecf.eclipse.org -Dpassword1=fliwatuetpassword

The accounts can also be gmail.com.

If you want to use a test account please let me know at slewis@composent.com.

Anonymous said...

Hi Scott,

I'm trying to use your example to call a remote method on different clients (though different machines) but I always get a timeout exception while calling a remote method. What am I doing wrong?

Here is my code snippet:

ISessionService tempService = ProvisioningActivator.getDefault().getService(ISessionService.class);
IRemoteServiceContainerAdapter remoteServiceContainerAdapter = tempService.getRemoteServiceContainerAdapter();
// get remote services
IRemoteServiceReference[] refs = remoteServiceContainerAdapter.getRemoteServiceReferences(null,
IInstalledFeaturesService.class.getName(),null);

// try to call a remote service on all connected user
for (int serviceNumber = 0; serviceNumber < refs.length; serviceNumber++) {

IRemoteService remService = remoteServiceContainerAdapter.getRemoteService(refs[serviceNumber]);
Assert.isNotNull(remService);
// get proxy for remote service
IInstalledFeaturesService featureService = (IInstalledFeaturesService) remService.getProxy();

// ************
// so far everything worked fine, but now a timeout exception is thrown
String userInfo = featureService.getUserInfo();
System.out.println(userInfo);
}

} catch (ECFException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Scott Lewis said...

Hi bstarchev,

You should try turning on the trace options (when running in the debugger) for the org.eclipse.ecf.provider.remoteservice
plugin. Do this for both the service 'server' as well as for the service 'client'. Then you should see the activity on both the client and the server when a remote call is made. It seems likely to me that the service is blocking/deadlocked somehow, and the response is never sent back to the client. If you want further help with this please LMK at slewis at composent.com and/or ecf-dev at eclipse.org and we'll get you going.

I assume that you are able to run the ECF remote services over XMPP tests on your XMPP accounts...is that right?

Anonymous said...

Hi Scott, thanks for the quick reply. I've sent you an email to discuss the problem further.

Regards,
Eugen

Anonymous said...

Hello Scott,

I would like to know if is possible to change the timeout value of the server for asynchronous communication, I am using the Eclipse ECF with R-OSGi and Equinox. When I modify the IRemoteCall timeout value with 3000 ms ...

remoteService.callAsync(createRemoteCall(), createRemoteCallListener());
System.out.println("callAsync invoked");

IRemoteCall createRemoteCall() {
return new IRemoteCall() {

public String getMethod() {
return "hello";
}
public Object[] getParameters() {
return new Object[] { "Asynch RemoteService Consumer" };
}
public long getTimeout() {
return 3000;
}
};
}

not work!!, only "timeout exceeded" after 120000 ms (2 min), this value is set in ch.ethz.iks.r_osgi.impl.ChannelEndpointImpl.

Thanks.

Scott Lewis said...

Hello Anonymous. I've forwarded your question about r-OSGi to the ecf-dev at eclipse.org mailing list, where the people that have worked on r-OSGi are available for consultation about how to reset the request timeout for r-OSGi provider.

Please join/monitor the conversation there.

Fer said...

Hello Scott,

When you create the IRemoteCall and you establish the timeout value (3000 ms) on Remote OSGi over XMPP using a sync call, what happen?, for example, if the request to server is longer than 3000 ms, throw a TimeoutException (ECFException) in the client?

I have tested it and not throws a TimeoutException, I have use different values of timeout and the result is always the same.

// Create remote call IRemoteCall remoteCall = new IRemoteCall() {
public String getMethod() { return "concat";
}
public Object[] getParameters() {
return new Object[]
{ "Eclipse", " is cool" };

}
public long getTimeout(){
return 3000;
}};

Best Regards,

Thanks!

Scott Lewis said...

Hi Fer. It would be a very good idea to move this discussion/such questions to ecf-dev at eclipse.org.

You say:

I have tested it and not throws a TimeoutException, I have use different values of timeout and the result is always the same.

I'm not sure what you are getting...are you getting a TimeoutException


The current XMPP provider ends up using the code in
org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject.callSynch(RemoteServiceRegistrationImpl, IRemoteCall)
to implement the timeout checking.

I would like to understand what you are seeing in your tests in terms of timeoutexception behavior...and if there is some problem/bug then we can/will address it.

But please consider continuing this dialog on ecf-dev at eclipse.org mailing list (see here for joining https://dev.eclipse.org/mailman/listinfo/ecf-dev

Fer said...

Hi Scott,

I have been comparing the async/sync call between r-OSGi and XMPP (for timeout value), I have seen that XMPP use this method

org.eclipse.ecf.provider.remoteservice.generic.RegistrySharedObject.callSynch(RemoteServiceRegistrationImpl, IRemoteCall)

version jar:
(org.eclipse.ecf.provider.remoteservice_3.0.0.v20090616-0832.jar)

while the r-OSGi use this other method

org.eclipse.ecf.internal.provider.r_osgi.callSync

version jar:
(org.eclipse.ecf.provider.r_osgi_3.0.0.v20090616-0832.jar)


I'm sorry, in my last post I was wrong, XMPP uses correctly the timeout value (specified in IRemoteCall), while r-OSGi no uses this value. The timeout specified in the async/sync call on the ECF provider level does not have any effect currently. I suppose that is a bug in ECF provider project of r-OSGi.
I hope already for the upcoming ECF 3.1 release.

Thanks!!.

Scott Lewis said...

Hi Fer...thanks...I see you've created bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=287663 and we'll address it with r-OSGi fixes/improvements.