Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EIG:Remoting"

(OSGi Remote Service Properties)
(Asynchronouse Remote Services (not yet OSGi standard))
 
(69 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Creating an OSGi Service<br>  ==
+
==[[EIG:Integrators Guide|Remoting]]==
 +
When we talk about services, we really talk about Java objects. We just call them services because of the way we use these Java objects. [http://www.google.com/search?q=soa+patterns Google for "SOA Patterns"] for more information on this topic. These Java objects are POJO's, as far as ECF is concerned. There is no need to implement anything from ECF in order for the "service" to be exposed as a remote service. The process to make a Java object (slash service) available on a remote machine is the mechanism we call "Remoting".
  
OSGi Services should be defined by/registered under a specific interface. Even though it's possible, with OSGi Remote Services the service should not be registered by the class name:<br>  
+
__TOC__
<source lang="java">public interface MyServiceInterface {
+
 
 +
===Creating an OSGi Service===
 +
OSGi Services should be defined by/registered under a specific interface.<br>  
 +
<source lang="java">public interface MyService {
 
      
 
      
     public String hello();
+
     public String hello(String name);
  
 
}
 
}
 
</source>  
 
</source>  
There is then some implementaions of this service: <br>  
+
There should then exist some implementation of this service: <br>  
<source lang="java">public class MyService implements MyServiceInterface {
+
<source lang="java">public class MyServiceImpl implements MyService {
  
     public String hello() {
+
     public String hello(String name) {
         return "Hello World!";
+
         return "Hi " + name + "! My name is Budhead.";
 
     }
 
     }
  
 
}
 
}
</source>  
+
</source>
== Registering an OSGi Remote Service<br>  ==
+
 
 +
=== Registering an OSGi Remote Service<br>  ===
  
 
The registration of an OSGi Remote Service is nearly the same as with any regular service in an OSGi Framework (e.g. Eclipse Equinox). The only additional thing you need to do is setting some service properties. For the Eclipse Communication Framework (ECF) only two properties are required: The "service.exported.interfaces" property marks the service for export (as an OSGi Remote Service) and defines under which interfaces this service can be exported. The "service.exported.configs" property is a list of configuration types (endpoint types) that should be used to export the service. The other properties are optional settings for the distribution provider.<br>  
 
The registration of an OSGi Remote Service is nearly the same as with any regular service in an OSGi Framework (e.g. Eclipse Equinox). The only additional thing you need to do is setting some service properties. For the Eclipse Communication Framework (ECF) only two properties are required: The "service.exported.interfaces" property marks the service for export (as an OSGi Remote Service) and defines under which interfaces this service can be exported. The "service.exported.configs" property is a list of configuration types (endpoint types) that should be used to export the service. The other properties are optional settings for the distribution provider.<br>  
  
=== OSGi Remote Service Properties<br>  ===
+
=== Service Properties<br>  ===
  
 
{|{{BMTableStyle}}
 
{|{{BMTableStyle}}
 
|-{{BMTHStyle}}
 
|-{{BMTHStyle}}
 
! Property Name  
 
! Property Name  
! Value(s)
+
! Type
 +
! Example
 
! Description
 
! Description
 
|-
 
|-
 
| service.exported.configs  
 
| service.exported.configs  
| {"ecf.generic.server","ecf.r-osgi.peer"}
+
| String+
| Types of endpoints that should be used for the export of the service. Distribution Providers create endpoints for each type they support.<br>
+
| "ecf.generic.server", "ecf.r_osgi.peer" etc.
 +
| Types of endpoints that should be used for the export of the service. Distribution Providers create endpoints for each type they support. See the [[ECF_Providers|list of Distribution Providers]] for all of the supported Providers and their configuration.
 
|-
 
|-
 
| service.exported.intents  
 
| service.exported.intents  
| [...]
+
| String+
 +
|
 
| Intents that the distribution provider must implement.<br>
 
| Intents that the distribution provider must implement.<br>
 
|-
 
|-
 
| service.exported.intents.extra  
 
| service.exported.intents.extra  
| [...]&nbsp;
+
| String+
 +
 
| Configurable intents the distribution provider must implement (based on a topology).<br>
 
| Configurable intents the distribution provider must implement (based on a topology).<br>
 
|-
 
|-
 
| service.exported.interfaces  
 
| service.exported.interfaces  
| {"*"}<br>
+
| String+
 +
| "*"  
 
| Interfaces to export.<br>
 
| Interfaces to export.<br>
 
|-
 
|-
 
| service.intents  
 
| service.intents  
| [...] <br>
+
| String+
 +
 
| Intents that are already implemented by the exported service implementation.<br>
 
| Intents that are already implemented by the exported service implementation.<br>
 
|}
 
|}
Line 53: Line 64:
 
<source lang="java">public class Activator implements BundleActivator {
 
<source lang="java">public class Activator implements BundleActivator {
  
     private MyServiceInterface myService = null;
+
     private MyService myService = null;
 
     private ServiceRegistration myServiceRegistration = null;
 
     private ServiceRegistration myServiceRegistration = null;
 +
 +
    private static BundleContext context;
 +
 +
    public static BundleContext getContext() {
 +
        return context;
 +
    }
  
 
     public void start(BundleContext bundleContext) throws Exception {
 
     public void start(BundleContext bundleContext) throws Exception {
         // Instantiate a service instance
+
        Activator.context = bundleContext;
         this.myService = new MyService();
+
 
 +
         // Instantiate a service
 +
         this.myService = new MyServiceImpl();
  
 
         // Register the service instance as an OSGi Remote Service
 
         // Register the service instance as an OSGi Remote Service
Line 64: Line 83:
 
         props.put("service.exported.interfaces", "*");
 
         props.put("service.exported.interfaces", "*");
 
         props.put("service.exported.configs", "ecf.r_osgi.peer");
 
         props.put("service.exported.configs", "ecf.r_osgi.peer");
         this.myServiceRegistration = bundleContext.registerService(MyServiceInterface.class.getName(), new MyService(), props);
+
         this.myServiceRegistration = bundleContext.registerService(MyService.class.getName(), this.myService, props);
 
     }
 
     }
  
 
     public void stop(BundleContext bundleContext) throws Exception {
 
     public void stop(BundleContext bundleContext) throws Exception {
 
         // Unregister the service
 
         // Unregister the service
         if(this.myServiceRegistration&nbsp;!= null) {
+
         if(this.myServiceRegistration != null) {
 
             this.myServiceRegistration.unregister();
 
             this.myServiceRegistration.unregister();
            this.myServiceRegistration = null;
 
            this.myService = null;
 
 
         }
 
         }
 +
        this.myServiceRegistration = null;
 +
        this.myService = null;
 
     }
 
     }
  
 
}
 
}
</source>  
+
</source>
== Using OSGi Remote Services<br>  ==
+
 
 +
=== Using OSGi Remote Services ===
  
 
If you would like to use OSGi Remote Services this is as simple as with regular services in the framework. You don't need to do anything different as usual, all remote services discovered by an ECF Discovery Provider are registered with the service registry of your OSGi Framework. So you either use the "getServiceReference(s)" method of your bundle context or create a service tracker for your service.<br>  
 
If you would like to use OSGi Remote Services this is as simple as with regular services in the framework. You don't need to do anything different as usual, all remote services discovered by an ECF Discovery Provider are registered with the service registry of your OSGi Framework. So you either use the "getServiceReference(s)" method of your bundle context or create a service tracker for your service.<br>  
Line 84: Line 104:
 
If you have local and remote services of the same type (e.g. registered under the same interface) in your OSGi Framework, local services can be filtered out by using an LDAP filter on the property "service.imported".  
 
If you have local and remote services of the same type (e.g. registered under the same interface) in your OSGi Framework, local services can be filtered out by using an LDAP filter on the property "service.imported".  
  
=== Example: Service Reference<br>  ===
+
===Example: Service Reference===
 
<source lang="java">ServiceReference myServiceReference = bundleContext.getServiceReference(MyServiceInterface.class.getName());
 
<source lang="java">ServiceReference myServiceReference = bundleContext.getServiceReference(MyServiceInterface.class.getName());
if(myServiceReference&nbsp;!= null) {
+
if(myServiceReference != null) {
     MyServiceInterface myService = (MyServiceInterface) bundleContext.getService(myServiceReference);
+
     MyService myService = (MyService) bundleContext.getService(myServiceReference);
     if(myService&nbsp;!= hull) {
+
     if(myService != hull) {
         System.out.println(myService.hello());
+
         System.out.println(myService.hello("Beavis"));
 
     } else {
 
     } else {
 
         throw new ServiceException("Service object is null.");
 
         throw new ServiceException("Service object is null.");
Line 96: Line 116:
 
     throw new ServiceException("Service reference is null.");
 
     throw new ServiceException("Service reference is null.");
 
}
 
}
</source>  
+
</source>
 +
 
 
=== Example: Service Tracker<br>  ===
 
=== Example: Service Tracker<br>  ===
<source lang="java">public class MyServiceInterfaceTracker extends ServiceTracker {
+
<source lang="java">public class MyServiceTracker extends ServiceTracker {
  
     public MyServiceInterfaceTracker() {
+
     public MyServiceTracker() {
         super(Activator.getContext(), MyServiceInterface.class.getName(), null);
+
         super(Activator.getContext(), MyService.class.getName(), null);
 
     }
 
     }
  
 
     @Override
 
     @Override
 
     public Object addingService(ServiceReference reference) {
 
     public Object addingService(ServiceReference reference) {
         System.out.println("MyServiceInterface has come.");
+
         MyService myService = null;
 +
        if(reference != null) {
 +
            myService = (MyService) Activator.getContext().getService(reference);
 +
            if(myService != null) {
 +
                System.out.println("MyServiceInterface has come.");
 +
            } else {
 +
                throw new ServiceException("Service object is null.");
 +
            }
 +
        } else {
 +
            throw new ServiceException("Service reference is null.");
 +
        }
 +
        return myService;
 
     }
 
     }
  
Line 115: Line 147:
  
 
}
 
}
</source>  
+
</source>
 +
 
 
=== Example: Service References with Filter  ===
 
=== Example: Service References with Filter  ===
 
<source lang="java">Filter filter = bundleContext.createFilter("(service.imported=*)");
 
<source lang="java">Filter filter = bundleContext.createFilter("(service.imported=*)");
ServiceReference[] myServiceReferences = bundleContext.getServiceReferences(MyServiceInterface.class.getName(), filter.toString());
+
ServiceReference[] myServiceReferences = bundleContext.getServiceReferences(MyService.class.getName(), filter.toString());
</source>  
+
</source>
== Asynchronouse Remote Services (not yet OSGi standard)<br>  ==
+
  
Usualy Remote Procedure Calls operates synchonously. However, ECF provides an API for asynchronouse calls that are executed in some other thread and don't block. This is sometimes desirable, for example, if your user interface thread is doing the calling, as remote methods can/could block for a much longer time than would be acceptable for users.<br>
+
=== Asynchronous Remote Services (not OSGi standard) ===
  
For the Implementation of an asynchronouse Remote Service the only thing you need to do is implementing an additional interface for your service. This interface should extend the IAsyncRemoteServiceProxy interface with an "Async" added to the interface name. This interface then should map all of the methods of your original interface with "Async" added to the method name and an additional callback parameter. Also this interface must be located in the same(!) package as the original interface of your service. The callback parameter should be an instance of the IAsyncCallback&lt;?&gt; interface with the original return type of your method as generic type parameter.  
+
Usualy Remote Procedure Calls operates synchronously. ECF provides an API for asynchronous calls that are executed in some other thread and don't block. This is sometimes desirable, for example, if your user interface thread is doing the calling, as remote methods can/could block for a much longer time than would be acceptable for users.<br>
<source lang="java">public interface MyServiceInterface extends IAsyncRemoteServiceProxy {
+
 
 +
This asynchronous Remote Service implementation is no OSGi standard. For background on the discussion about asynchronous remote services invocation in general and possible future standardization by the OSGI standards organization see [http://www.osgi.org/blog/2010/04/calling-your-cake-and-sending-it-too.html Peter Kriens blog entry], and [http://eclipseecf.blogspot.com/2010/04/osgi-remote-services-and-ecf.html Scott Lewis' blog entry].<br>
 +
 
 +
For the Implementation of an asynchronous Remote Service the only thing you need to do is implementing an additional interface for your service. This interface should extend the IAsyncRemoteServiceProxy interface with an "Async" added to the interface name. This interface then should map all of the methods of your original interface with "Async" added to the method name and an additional callback parameter. Also this interface must be located in the same(!) package as the original interface of your service. The last parameter of the asynchronous method should then be an instance of the IAsyncCallback&lt;?&gt; interface with the original return type of your method as generic type parameter.<br>
 +
 
 +
Another approach (next to IAsyncCallback&lt;?&gt;) to achieving asynchronous invocation of remote services are futures.  Future objects allow the consumer to perform operations in between initiating a remote call and receiving a result.<br>
 +
 
 +
Both of these approaches can be used seperate and also togehter.
 +
 
 +
<source lang="java">public interface MyServiceAsync extends IAsyncRemoteServiceProxy {
 
      
 
      
     public void helloAsync(IAsyncCallback&lt;String&gt; callback);
+
     public void helloAsync(String name, IAsyncCallback<String> callback);
 +
    // and/or
 +
    public IFuture helloAsync(String name);
  
 
}
 
}
 
</source>
 
</source>
Note that with this you will have direct dependencies to ECF bundles. Also some of the distribution providers still don't handle the registration of multiple interfaces correctly.  
+
Note that with this you will have direct dependencies to ECF bundles. Also some of the distribution providers still don't handle the registration of multiple interfaces correctly.
  
 
=== Example ===
 
=== Example ===
<source lang="java">if(myService instanceof MyServiceInterfaceAsync) {
+
<source lang="java">if(myService instanceof MyServiceAsync) {
     System.out.println((MyServiceInterfaceAsync)myService.helloAsync(new MyServiceInterfaceCallback()));
+
     ((MyServiceAsync)myService).helloAsync("Beavis", new MyServiceCallback());
 
}
 
}
 
</source>
 
</source>
 
<source lang="java">
 
<source lang="java">
public class MyServiceInterfaceCallback implements IAsyncCallback&lt;String&gt; {
+
public class MyServiceCallback implements IAsyncCallback<String> {
  
 
     @Override
 
     @Override
Line 155: Line 198:
 
</source>
 
</source>
  
== Futures with Remote Services (no OSGi standard) ==
+
=== Example (Future) ===
 
+
This initiates a remote call, performs some additional local operations and then gets a result from the future.
[...]
+
<source lang="java">
 
+
IFuture future = ((MyServiceAsync)myService).helloAsync("Beavis");
== Implementing an ECF Distribution Provider<br>  ==
+
// Do other local operations here...
 
+
String result = (String) future.get();
[...]<br>
+
System.out.println(result);
 +
</source>

Latest revision as of 01:10, 24 January 2013

Remoting

When we talk about services, we really talk about Java objects. We just call them services because of the way we use these Java objects. Google for "SOA Patterns" for more information on this topic. These Java objects are POJO's, as far as ECF is concerned. There is no need to implement anything from ECF in order for the "service" to be exposed as a remote service. The process to make a Java object (slash service) available on a remote machine is the mechanism we call "Remoting".

Creating an OSGi Service

OSGi Services should be defined by/registered under a specific interface.

public interface MyService {
 
    public String hello(String name);
 
}

There should then exist some implementation of this service:

public class MyServiceImpl implements MyService {
 
    public String hello(String name) {
        return "Hi " + name + "! My name is Budhead.";
    }
 
}

Registering an OSGi Remote Service

The registration of an OSGi Remote Service is nearly the same as with any regular service in an OSGi Framework (e.g. Eclipse Equinox). The only additional thing you need to do is setting some service properties. For the Eclipse Communication Framework (ECF) only two properties are required: The "service.exported.interfaces" property marks the service for export (as an OSGi Remote Service) and defines under which interfaces this service can be exported. The "service.exported.configs" property is a list of configuration types (endpoint types) that should be used to export the service. The other properties are optional settings for the distribution provider.

Service Properties

Property Name Type Example Description
service.exported.configs String+ "ecf.generic.server", "ecf.r_osgi.peer" etc. Types of endpoints that should be used for the export of the service. Distribution Providers create endpoints for each type they support. See the list of Distribution Providers for all of the supported Providers and their configuration.
service.exported.intents String+ Intents that the distribution provider must implement.
service.exported.intents.extra String+ Configurable intents the distribution provider must implement (based on a topology).
service.exported.interfaces String+ "*" Interfaces to export.
service.intents String+ Intents that are already implemented by the exported service implementation.

Example

public class Activator implements BundleActivator {
 
    private MyService myService = null;
    private ServiceRegistration myServiceRegistration = null;
 
    private static BundleContext context;
 
    public static BundleContext getContext() {
        return context;
    }
 
    public void start(BundleContext bundleContext) throws Exception {
        Activator.context = bundleContext;
 
        // Instantiate a service
        this.myService = new MyServiceImpl();
 
        // Register the service instance as an OSGi Remote Service
        Properties props = new Properties();
        props.put("service.exported.interfaces", "*");
        props.put("service.exported.configs", "ecf.r_osgi.peer");
        this.myServiceRegistration = bundleContext.registerService(MyService.class.getName(), this.myService, props);
    }
 
    public void stop(BundleContext bundleContext) throws Exception {
        // Unregister the service
        if(this.myServiceRegistration != null) {
            this.myServiceRegistration.unregister();
        }
        this.myServiceRegistration = null;
        this.myService = null;
    }
 
}

Using OSGi Remote Services

If you would like to use OSGi Remote Services this is as simple as with regular services in the framework. You don't need to do anything different as usual, all remote services discovered by an ECF Discovery Provider are registered with the service registry of your OSGi Framework. So you either use the "getServiceReference(s)" method of your bundle context or create a service tracker for your service.

If you have local and remote services of the same type (e.g. registered under the same interface) in your OSGi Framework, local services can be filtered out by using an LDAP filter on the property "service.imported".

Example: Service Reference

ServiceReference myServiceReference = bundleContext.getServiceReference(MyServiceInterface.class.getName());
if(myServiceReference != null) {
    MyService myService = (MyService) bundleContext.getService(myServiceReference);
    if(myService != hull) {
        System.out.println(myService.hello("Beavis"));
    } else {
        throw new ServiceException("Service object is null.");
    }
} else {
    throw new ServiceException("Service reference is null.");
}

Example: Service Tracker

public class MyServiceTracker extends ServiceTracker {
 
    public MyServiceTracker() {
        super(Activator.getContext(), MyService.class.getName(), null);
    }
 
    @Override
    public Object addingService(ServiceReference reference) {
        MyService myService = null;
        if(reference != null) {
            myService = (MyService) Activator.getContext().getService(reference);
            if(myService != null) {
                System.out.println("MyServiceInterface has come.");
            } else {
                throw new ServiceException("Service object is null.");
            }
        } else {
            throw new ServiceException("Service reference is null.");
        }
        return myService;
    }
 
    @Override
    public void removedService(ServiceReference reference, Object service) {
        System.out.println("MyServiceInterface has gone.");
    }
 
}

Example: Service References with Filter

Filter filter = bundleContext.createFilter("(service.imported=*)");
ServiceReference[] myServiceReferences = bundleContext.getServiceReferences(MyService.class.getName(), filter.toString());

Asynchronous Remote Services (not OSGi standard)

Usualy Remote Procedure Calls operates synchronously. ECF provides an API for asynchronous calls that are executed in some other thread and don't block. This is sometimes desirable, for example, if your user interface thread is doing the calling, as remote methods can/could block for a much longer time than would be acceptable for users.

This asynchronous Remote Service implementation is no OSGi standard. For background on the discussion about asynchronous remote services invocation in general and possible future standardization by the OSGI standards organization see Peter Kriens blog entry, and Scott Lewis' blog entry.

For the Implementation of an asynchronous Remote Service the only thing you need to do is implementing an additional interface for your service. This interface should extend the IAsyncRemoteServiceProxy interface with an "Async" added to the interface name. This interface then should map all of the methods of your original interface with "Async" added to the method name and an additional callback parameter. Also this interface must be located in the same(!) package as the original interface of your service. The last parameter of the asynchronous method should then be an instance of the IAsyncCallback<?> interface with the original return type of your method as generic type parameter.

Another approach (next to IAsyncCallback<?>) to achieving asynchronous invocation of remote services are futures. Future objects allow the consumer to perform operations in between initiating a remote call and receiving a result.

Both of these approaches can be used seperate and also togehter.

public interface MyServiceAsync extends IAsyncRemoteServiceProxy {
 
    public void helloAsync(String name, IAsyncCallback<String> callback);
    // and/or
    public IFuture helloAsync(String name);
 
}

Note that with this you will have direct dependencies to ECF bundles. Also some of the distribution providers still don't handle the registration of multiple interfaces correctly.

Example

if(myService instanceof MyServiceAsync) {
    ((MyServiceAsync)myService).helloAsync("Beavis", new MyServiceCallback());
}
public class MyServiceCallback implements IAsyncCallback<String> {
 
    @Override
    public void onSuccess(String result) {
        System.out.println(result);
    }
 
 
    @Override
    public void onFailure(Throwable e) {
        e.printStackTrace();
    }
 
}

Example (Future)

This initiates a remote call, performs some additional local operations and then gets a result from the future.

IFuture future = ((MyServiceAsync)myService).helloAsync("Beavis");
// Do other local operations here...
String result = (String) future.get();
System.out.println(result);

Back to the top