Eclipse from the bottom up

The view of the Eclipse world from the bottom of the stack

Monday, March 05, 2007

My first (and second) OSGi Service

It seems everywhere I look these days, I see OSGi mentioned. So in an attempt to be fashionable (and because I think it was the right thing to do) I have made a couple of new features that have been added the Eclipse Platform available as OSGI services (I should note that these features will appear in the next integration build). The new services are:
  • IProxyService: a service that allows clients to access and modify the proxy settings for HTTP, HTTPS (or SSL) and SOCKS and ensures that the values specified are put into the corresponding Java system properties. This service is located in the org.eclipse.core.net plug-in and there is an associated preference page for setting the proxies.
  • IJSchService: a service that complements the JSch SSH2 client by ensuring that JSch is properly configured (using settings from the SSH2 preference page) when clients attempt to make SSH2 connections. The service also uses the proxy service to configure JSch proxies. The JSch service is found in the org.eclipse.jsch.core plug-in while a generic prompter can be found in the org.eclipse.jsch.ui plug-in.
In order to use these services, you need to obtain them using OSGi. Niel provides some general articles on working with OSGi services. To illustrate, here's an example of how you can use the JSch service (and, indirectly, the proxy service) to make a connection using a proxy.

The first thing you need to do is add a service tracker in you bundle activator (or, in the old world lingo, add a tracker to your plug-in class). Here's the code I needed to add to my Activator class.

private ServiceTracker tracker;

public void start(BundleContext context) throws Exception {
super.start(context);
tracker = new ServiceTracker(
getBundle().getBundleContext(),
IJSchService.class.getName(),
null);
tracker.open();
}

public void stop(BundleContext context) throws Exception {
tracker.close();
super.stop(context);
}

public org.eclipse.jsch.core.IJSchService getJSchService() {
return (IJSchService)tracker.getService();
}

Once you have that, you can make an SSH2 connection in the following way:

IJSchService service = CVSProviderPlugin.getPlugin().getJSchService();
if (service == null)
// Service is not available
Session session = service.createSession(hostname, port, username);
int timeout = 60000;
session.setTimeout(timeout);
if (password != null)
session.setPassword(password);
session.setUserInfo(new org.eclipse.jsch.ui.UserInfoPrompter(session));
service.connect(session, timeout, monitor);

The above connection methods will use any proxies that are specified in the proxy service. However, with the JSch service, you can also use proxies with other types of connections (e.g. CVS pserver). Here's how:

private Proxy getProxy() {
IJSchService service = Activator.getInstance().getJSchService();
if (service == null)
return null;
Proxy proxy = service.getProxyForHost(
hostName,
IProxyData.HTTPS_PROXY_TYPE);
if (proxy == null)
proxy = service.getProxyForHost(
hostName,
IProxyData.SOCKS_PROXY_TYPE);
return proxy;
}

If the returned proxy is null, you can make a direct connection. Otherwise, you can use the Proxy#connect method to connect to a specific host. There's a helper method on the JSch service to connect to a proxy in a responsive fashion (i.e. respond to cancellation) that you can use as well.

service.connect(proxy, hostName, port, timeout, monitor)
So, there you have it. No more need to define static classes for accessing singleton services. Initially, I found accessing the OSGi services a bit more cumbersome than the static class approach but I think the added flexibility is worth it.