Tuesday, May 01, 2018

ECF Photon supports OSGi Async Remote Services

In a previous post, I indicated that ECF Photon/3.14.0 will support the recently-approved OSGi R7 specification.   What does this support provide for  developers?

Support osgi.async remote service intent

The OSGi R7 Remote Services specification has been enhanced with remote service intents.  Remote Service Intents allow service authors to specify requirements on the underlying distribution system in a standardized way.   Standardization of service behavior guarantees the same runtime behavior across distribution providers and implementations.

The osgi.async intent allows the service interface to use return types such as Java8's CompletableFuture or OSGi's Promise.   With a supporting distribution provider, the proxy will automatically implement the asynchronous/non-blocking behavior for the service consumer.

For example, consider a service interface:
public interface Hello {
    CompletableFuture<String> hello(String greetingMessage);
}
When an implementation of this service is registered and exported as a remote service with the osgi.async intent:
@Component(property = { "service.exported.interfaces=*", "service.intents=osgi.async" })
public class HelloImpl implements Hello {
    public CompletableFuture<String> hello(String greetingMessage) {
          CompletableFuture<String> future = new CompletableFuture<String>();
          future.complete("Hi.  This a response to the greeting: "+greetingMessage);
          return future;
    }
}
Then when a Hello service consumer (on same or other process) discovers, imports and then remote service is injected by DS:
@Component(immediate=true)
public class HelloConsumer {

    @Reference
    private Hello helloService;

    @Activate
    void activate() throws Exception {
        // Call helloService.hello remote service without blocking
        helloService.hello("hi there").whenComplete((result,exception) -> {
            if (exception != null)
                exception.printStackTrace(exception);
            else
                System.out.println("hello service responds: " + result);
        });
    }
}
The injected helloService instance (a distribution-provider-constructed proxy) will automatically implement the asynchronous remote call.   Since the proxy is constructed by the distribution provider, there is no need for the consumer to implement anything other than calling the 'hello' method and handling the response via the Java8-provided whenComplete method.   Java8's CompletionStage, Future, and OSGi's Promise are also supported return types.  (Only the return type is used to identify asynchronous remote methods, any method name can be used).  For example: the following signature is also supported as an async remote service:
public interface Hello {
    org.osgi.util.promise.Promise<String> hello(String greetingMessage);
}

Further, OSGi R7 Remote Services supports a timeout property:
@Component(property = { "service.exported.interfaces=*", "service.intents=osgi.async", "osgi.basic.timeout=20000" })
public class HelloImpl implements Hello {
    public CompletableFuture<String> hello(String greetingMessage) {
          CompletableFuture<String> future = new CompletableFuture<String>();
          future.complete("Hi.  This a response to the greeting: "+greetingMessage);
          return future;
    }
}
With ECF's RSA implementation and distribution providers, this timeout will be honored by the underlying distribution system. That is, if the remote implementation does not return within 20000ms, then the returned CompletableFuture will complete with a TimeoutException.

Async Remote Services make it very easy for service developers to define, implement, and consume loosely-coupled and dynamic asynchronous remote services.   It also makes asynchronous remote service contracts transport independent, allowing the swapping of distribution providers or creating/using custom providers without changes to the service contract.

For the documented example code, see here

Monday, April 23, 2018

ECF Photon adds Gogo Commands

A third major enhancement for ECF's implementation of OSGi Remote Services is the addition of Apache Gogo console commands for examining the existing state of remote services, and the ability to export a service and import an endpoint from the OSGi console.

See this wiki page describing the new commands and their usage.


Thursday, April 19, 2018

ECF Photon supports Bndtools

A second major enhancement for ECF Photon is adding support for using Bndtools to develop and test OSGi Remote Services.   Bndtools is increasingly popular for developing OSGi-based applications and frameworks, and we've added support for Bndtools Workspace, Project, and Run Descriptor templates for developing and testing remote services.

Initial documentation is available at Bndtools Support for Remote Services Development.

Note that these templates and the RSA impl may change slightly before ECF Photon, and new/additional templates will be added to (e.g.) support other distribution and discovery providers.


Monday, April 16, 2018

ECF Photon supports OSGI R7

ECF Photon has several major enhancements.   I'll blog about these enhancements individually over the coming weeks, starting with

Support for OSGI R7 Remote Services

In the R7 final draft specification (chapter 100) detail was added about the use of Remote Service Intents.   RS Intents describe a distribution provider's abstract capabilities.    By way of example, several new standard intents have been defined, including osgi.basic and osgi.async.   

The osgi.basic intent requires that a distribution provider support a remote service-specific timeout, as well as serialization of remote service arguments and return values include DTOs (Data Type Objects), java primitives, maps, collections, lists, OSGI Version, etc.   

The osgi.async intent requires that remote service method signatures using CompletableFuture, Future, and OSGI's Promise be supported directly by the distribution provider.   This allows non-blocking asynchronous remote services to be easily declared in the service interface, and implemented by the distribution provider.  Here is an example remote service declaration that demonstrates how the osgi.async intent can be used.   In a forthcoming tutorial, I'll show how such a small service can be easily defined, implemented, and remoted using ECF Remote Services.

ECF's remote services impl has multiple distribution providers, and open APIs for creating custom or extension providers.   Most of the existing ECF distribution providers already available have been updated to implement the R7-standardized intents.   Others will be updated prior to and after Photon release.


Monday, February 12, 2018

Python 3 and Import Hooks for OSGi Services

In a previous post I described using Python for implementing OSGi Services.   This Python<->Java service bridge allows Python-provided/implemented OSGi services called from Java, and Java-provided/implemented OSGi Services called from Python.   OSGi Remote Services provides a standardized way of communicating service meta-data (e.g. service contracts, endpoint meta-data) between Java and Python processes.

As this Java<->Python communication conforms to the OSGi Remote Services specification, everything is completely inter-operable with Declarative Services and/or other frameworks based upon OSGi Services.  It will also run in any OSGi R5+ environment, including Eclipse, Karaf, OSGi-based web servers, or other OSGi-based environments.

Recently, Python 3 has introduced the concept of an Import Hook.   An import hook allows the python path and the behavior of the python import statement to be dynamically or extended. 

In the most recent version (2.7) of the ECF Py4j Distribution Provider, we use import hooks so that Python module import is resolved by a Java-side OSGi ModuleResolver service.   For example, as described in this tutorial, this Python statement
from hello import HelloServiceImpl
imports the hello.py module as a string loaded from within an OSGi bundle.  Among other things, this allows OSGi dynamics to be used to add and remove modules from the python path without stopping and restarting either the Java or the Python processes.


Wednesday, December 27, 2017

Remote Services without OSGi bundles

Remote Services provides a dynamic, transport-independent, simple, modular way to expose micro services.   ECF has created a spec-compliant implementation along with a large and growing number of open and extensible distribution providers.   

Remote services are frequently useful for fog/edge use cases, where the communication transports (e.g. MQTT) may be different than those typically used in the cloud (e.g. http/https, jaxrs, enterprise messaging, etc).   

Typically, remote services are run on OSGi-based frameworks and apps such as Equinox, Felix, Karaf, Eclipse, and others, and indeed ECF's RSA implementation works very well in any of these environments.   

Perhaps less well known, however, is that remote services can be used in other inter-process environments...for example between Java and Python.  

It's also possible to use ECF remote services without an OSGi framework, i.e. running only as Java applications.   This repository has an example of using ECF remote services without an OSGi framework.   The projects are Java applications (no OSGi framework assumed), on both the remote service provider side, as well as the remote service consumer side.   The examples may be run within Eclipse by using the launch configs in the example projects.

Most of the benefits of OSGi Remote Services are still available...for example the ability to use multiple distribution providers for a service, the ability to remotely discover services and dynamically respond to network failure, and the ability to use the OSGi service registry for service dynamics, and service injection.   Also, the service definition, implementation, registration and lookup are exactly the same whether via an OSGi bundle or a Java application.   This allows services to be defined consistently across runtime environments in addition to cross-distribution mechanisms.

Please clone the ServiceRegistry github repository and give things a try!





Wednesday, December 13, 2017

Remote Services between Python and Java

ECF's implementation of OSGi Remote Services allows multiple distribution providers, which are responsible for the actual rpc communication required by remote services.   Here is a list of ECF distribution providers we've created.

Using Py4j and Google Protocol Buffers, we've recently enhanced an ECF distribution provider that allows the use of remote services (and Remote Service Admin) between OSGi and Python.   Service impls can be in either Java or Python, and consumers can be either Java or Python.     Protocol Buffers can be used to efficiently serialize arguments and return values.

The only dependencies are on OSGi, Py4j, and Google Protocol buffers, so this distribution provider can be used in Eclipse or other OSGi environments like Karaf.

Get the most recent release, with examples and source code at this github repository.