Showing posts with label remoteserviceadmin. Show all posts
Showing posts with label remoteserviceadmin. Show all posts

Tuesday, October 19, 2021

OSGi Services with gRPC - Let's be reactive

ECF has just introduced an upgrade to the grpc distribution provider.   Previously, this distribution provider used ReaxtiveX java version 2 only.  With this release, ReactiveX java version 3 is also supported.

As many know, gRPC allows services (both traditional call/response [aka unary] and streaming services) to be defined by a 'proto3' file.  For example, here is a simple service with four methods, one unary (check) and 3 streaming (server streaming, client streaming, and bi-directional streaming)
syntax = "proto3";

package grpc.health.v1;

option java_multiple_files = true;
option java_outer_classname = "HealthProto";
option java_package = "io.grpc.health.v1.rx3";

message HealthCheckRequest {
  string message = 1;
}

message HealthCheckResponse {
  enum ServingStatus {
    UNKNOWN = 0;
    SERVING = 1;
    NOT_SERVING = 2;
    SERVICE_UNKNOWN = 3;  // Used only by the Watch method.
  }
  ServingStatus status = 1;
}

service HealthCheck {
  // Unary method
  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
  // Server streaming method
  rpc WatchServer(HealthCheckRequest) returns (stream HealthCheckResponse);
  // Client streaming method
  rpc WatchClient(stream HealthCheckRequest) returns (HealthCheckResponse);
  // bidi streaming method
  rpc WatchBidi(stream HealthCheckRequest) returns (stream HealthCheckResponse);
}
The gRPC project provides a plugin so that when protoc is run, java code (or other language code) is generated that can then be used on the server and/or clients.

With some additional plugins, the classes generated by protoc can use the ReactiveX API for generating code.   So, for example, here is the java code generated by running protoc, grpc, reactive-grpc, and the osgi-generator plugins on the above HealthCheck service definition.  

Note in particular the HealthCheckService interface generated by the osgi-generator protoc plugin:
package io.grpc.health.v1.rx3;

import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.core.Flowable;

@javax.annotation.Generated(
value = "by grpc-osgi-generator (REACTIVEX) - A protoc plugin for ECF's grpc remote services distribution provider at https://github.com/ECF/grpc-RemoteServiceSProvider ",
comments = "Source: health.proto.  ")
public interface HealthCheckService {
    /**
     * <pre>
     *  Unary method
     * </pre>
     */
    default Single<io.grpc.health.v1.rx3.HealthCheckResponse> check(Single<io.grpc.health.v1.rx3.HealthCheckRequest> requests)  {
        return null;
    }
    /**
     * <pre>
     *  Server streaming method
     * </pre>
     */
    default Flowable<io.grpc.health.v1.rx3.HealthCheckResponse> watchServer(Single<io.grpc.health.v1.rx3.HealthCheckRequest> requests)  {
        return null;
    }
    /**
     * <pre>
     *  Client streaming method
     * </pre>
     */
    default Single<io.grpc.health.v1.rx3.HealthCheckResponse> watchClient(Flowable<io.grpc.health.v1.rx3.HealthCheckRequest> requests)  {
        return null;
    }
    /**
     * <pre>
     *  bidi streaming method
     * </pre>
     */
    default Flowable<io.grpc.health.v1.rx3.HealthCheckResponse> watchBidi(Flowable<io.grpc.health.v1.rx3.HealthCheckRequest> requests)  {
        return null;
    }
}

Note that it uses the two ReactiveX 3 classes: io.reactivex.rxjava3.core.Single, and io.reactivex.rxjava3.core.Flowable. These two classes provide api for event-driven/reactive sending and receiving of unary (Single) and streaming (Flowable) arguments and return values.

The ReactiveX API...particularly Flowable...makes it very easy to implement both consumers and implementers of the streaming API, while maintaining ordered delivery and non-blocking communication.

For example, this is a simple implementation of the HealthCheckService. Note how the Single and flowable methods are able to express the implementation logic through methods such as Flowable.map.
Here is a simple implementation of a consumer of the HealthCheckService.

The use of the ReactiveX API simplifies both the implementation and the consumer use of both unary and streaming services. As an added bonus: the reactive-grpc library used in the ECF Distribution provider provides *flow-control* using backpressure.

In next article I'll describe how OSGi Remote Services can be easily used to export, publish, discover, and import remote services with full support for service versioning, security, and dynamics. I'll also describe one can use tools like maven or bndtools+eclipse to generate source code (as above) from a proto3 file and easily run a generated service as an OSGi Remote Service.

Tuesday, June 22, 2021

gRPC and OSGi Remote Services

 gRPC is a popular framework for creating high-performance remote procedure call-based microservices.  

OSGi Remote Services is a transport-agnostic specification for creating dynamic, versionable, modular, remote services.

The ECF project provides an open implementation of the OSGi Remote Services spec, and has a provider implementation based-upon gRPC.   What this means is that gRPC can be used to create and run as an OSGi remote service, with all the support for service dynamics (particularly important for network-based services), versioning, and other features provided by OSGi remote services.

The architectural fit between gRPC and OSGi Remote Services is very good, since gRPC is concerned with transport-level efficiency (i.e. http/2, binary serialization format), and OSGi Remote Services are completely transport-agnostic, and focuses instead upon service-level concerns (e.g. dynamics, versioning, and service discovery).

gRPC offers support for server and client-based streaming.   In ECF's implementation, streaming rpcs are mapped to the reactivex api.  This means that consumers and implementers of a streaming rpc can simply call methods and provide callbacks (using Flowable), and non-blocking streaming calls will be made.  In addition, the use of reactivex and backpressure will result in transport-level flow control for these streaming APIs!

Another advantage of gRPC for OSGi remote services is it's polyglot nature.   This means that if (for example) a gRPC remote service is run as an OSGi/Java server, clients can be easily implemented in any of the languages supported by gRPC.  As well, servers written in some other language can easily created and accessed from OSGi consumers.  An example of this is the ECF etcd3 discovery provider, which communicates with an etcd server (written in Go) to publish and discover OSGi remote services.

Finally, with bndtools (an Eclipse plugin for OSGi bundle development), ECF Remote Service workspace template, and it's support for generating code as part of Eclipse's incremental build, gRPC code generation can be seemlessly integrated into the Eclipse development environment so that gRPC code generation, compile, and bundle packaging can happen immediately and continuously as part of gRPC remote service development.  For a video tutorial demonstrating this, please see here.

Thursday, January 07, 2021

ECF 3.14.19 released - simplify remote service discovery via properties

 ECF 3.14.19 has been released.

Along with the usual bug fixes, this release includes new documentation on the use of properties for discovering and importing remote services.   The docs describe the use of properties files for simplifying the import of remote services.   

This capability is especially useful for Eclipse RCP clients accessing Jax-RS/REST remote services.

Patrick Paulin describes a production usage his blog posting here.

Tuesday, December 08, 2020

Using properties to simplify discovery of OSGi Remote Services

OSGi Remote Services are discovered by ECF's Remote Services implementation in two ways:  

1. Via a network discovery protocol provider such as:  Zeroconf, jSLP, etcd, Zookeeper, or some custom protocol

2. Via an xml format known as an Endpoint Description Extender Format (EDEF)

 The EDEF format is specified by the OSGi Remote Service Admin specification.   

When importing an EDEF-defined remote service, it's typically necessary to construct the entire EDEF file 'by hand' rather than having he EDEF generated automatically.  This can be quite complicated to construct by hand as some properties are required, others are optional and it's not obvious what all of the values must be for successful import.

A new capability has been added to ECF's Remote Service Admin implementation that allows EDEF Properties to be used with the EDEF, thus simplifying the creation of remote service consumers that use EDEF for import.

This capability was added to support the usage of JaxRS Remote Services in an Eclipse RCP client.  See a description of this use case here.



Monday, September 21, 2020

Using gRPC-java code generation to create OSGi Services

OSGi Services are usually first created by declaring a java service interface class.  As an OSGi service, this interface class serves as both the name for the service in the service registry, and defines the service contract (i.e. the interface method signatures...i.e. the method name, argument types, and return types) for that version of the service.

gRPC (Google RPC) is a popular and high-performance rpc approach that allows developers to define networked services based upon protocol buffers (proto3).

By extending bndtools recently-added code generation capability, it's now possible to generate an OSGi (remote) service API from just a proto3 service declaration.  All the classes necessary for an OSGi Remote Service API (service interface, arg and return types) can be generated by bndtools within Eclipse from a single proto3 file, immediately and completely.

Ready to implement-and-consume OSGi Services can be generated by Eclipse+bndtools + a proto3 service declaration.

Further, the proto3 service declaration can be modified, and the tooling will immediately generate new service API classes, compile, and package them into a bundle, all from within Eclipse+bndtools.

To get this bndtools-grpc generation with an example see here.




Tuesday, March 03, 2020

ECF 3.14.7 released

ECF 3.14.7 has been released and may be downloaded here.

In concert with this bug fix release have been a number of additions to ECF's github projects for Remote Services Development.

Distribution and Discovery Providers

Enhanced:  Hazelcast-based Distribution Provider v1.7.0.  Upgraded to use Hazelcast 4
Enhanced:  System and Service-Properties docs for Distribution Providers and Discovery Providers

Bndtools Development

Enhanced:  Bndtools Workspace template with new Bndrun templates for Remote Services Development
Enhanced:  Tutorial for using Bndtools for Remote Services Development

Saturday, August 31, 2019

OSGi Remote Services with Apache Dubbo

ECF's implementation of OSGi R7 Remote Services allows for replacing the underlying distribution system (repsonsible for the object serialization, transport, and other things). 

This makes it relatively easy to replace one kind of distribution (e.g. Jersey, ActiveMQ) with other/new distribution systems. 

Apache Dubbo has recently been contributed to Apache, and we've created a distribution provider based upon Apache Dubbo.

Here's a list of open ECF Remote Service distribution providers.   If you would like Remote Services support for a particular transport, or you've created your own distribution (or discovery) based upon some other transport and wish to make it available to others please let us know.


Wednesday, April 03, 2019

New Release: Python<->Java Remote Services

There is a new release (2.9.0) of the ECF distribution provider for OSGi R7 Remote Services between Java and Python.

This release has:

An upgraded version of Py4j
An upgraded version of Google Protocol Buffers
Enhancements to the distribution provider based upon the improved Py4j and Protobuf libs

In this previous blog posting there are links to tutorials and examples showing how to use remote services between Python<->Java.

Python<->Java remote services can be consumed or implemented in either Java or Python.

Monday, February 25, 2019

RESTful OSGi R7 Remote Services with Jersey 2.28 or Apache CXF 3.3

For some time, ECF has had remote service distribution providers that use the Jersey or the CXF implementation of standard Java API for RESTful Web Services (JaxRS). 

These distribution providers allow OSGi R7 Remote Services to be defined via JaxRS annotations and implemented by either Jersey 2.28 or CXF 3.3

OSGi R7 Remote Services provides support for renite service discovery, dynamics, versioning, configuration and extension of the distribution providers, and asynchronous remote calls as well as other features of the OSGi R7 Remote Services and Remote Service Admin specs.

This tutorial shows the use of OSGi Remote Services with these JaxRS distribution providers on Apache Karaf.

There is also a new version of the ECF Bndtools workspace template with example Bndtools projects showing the use of these distribution providers to define, configure, run and deploy RESTful OSGi R7 Remote Services with Bndtools 4.2+.

Sunday, November 04, 2018

ECF 3.14.4 released

ECF 3.14.4 was recently released.  This was a bug-fix release.  There are notes on some of the recent additions here.

Wednesday, August 22, 2018

OSGi Remote Services Between Python and Java

In a previous post, I described the support for OSGi Remote Services and Remote Service Admin in iPOPO 0.8.0 release.   The previous post refers to a tutorial showing a Python service impl and Python consumer.

Python<->Java Distribution Provider

Included with iPOPO 0.8.0 is a distribution provider that allows remote services between Java and Python frameworks.   For example, this is a tutorial, that uses Karaf on the Java side as the remote service implementation, and has a Python consumer that calls the Java-implemented remote service.

Python Service Implementation with Java Consumers

This distribution provider also supports Python-implemented remote services, with Java/OSGi consumers.   With iPOPO for dynamic service injection in Python, and Declarative Services for Java/OSGi, this allows very easy Python<->Java service-level interaction, with support for all dynamics, RSA management agent, extensible/customizable topology management, management of complicated service dependencies, pluggable local and network discovery, and other RS/RSA features handled consistently in both Java and Python.  As well, the use of OSGi-specified EndpointDescription service metadata allows service-level interoperability across languages.

Python<->Java with Protocol Buffers Serialization

Also included with this distribution provider is serialization using Google's protocol buffers.  This allows open, extensible, and efficient rpc between Python and Java.


Tuesday, August 21, 2018

Python for OSGi Remote Services

The iPOPO project is a Python implementation of key parts of a standard OSGi framework...e.g. bundles, the service registry and servicereference api, and a dynamic service injection framework similar to the Apache iPOJO project...thus the name iPOPO.

With the 0.8.0 release of iPOPO, there is now a Python implementation of the OSGi Remote Services and Remote Service Admin (RSA) specifications.   To distinguish from the previously-provided remote services in iPOPO, this is known as RSA Remote Services.

iPOPO's RSA Remote Services has many of the same advantages as Java-based Remote Services/RSA.  Some of these advantages:

Decoupling - name/service contract is decoupled from the implementation (and distribution)

Dynamics - The service registry dynamics behavior, along with all notifications, etc is available in Python

Injection and Service Dependency Management - iPOPO provides service injection and dependency management, built upon the Python API

Standard RemoteServiceAdmin Management Agent, RSA Console Commands

API for Distribution and Discovery Providers - There are documented APIs for creating new distribution and discovery providers, making it easy to support other transports and implementations for distribution (e.g. REST/JaxRS, Jsonrpc, MQTT, Zeroconf Discovery, etc).

Other advantages of Java-based OSGi services are described here.   All of these advantages apply to Python/iPOPO-based services, but Python can be used to implement and/or consume services.

Currently, there are two distribution providers included with iPOPO 0.8.0:  XmlRpc, Python-Java and one discovery provider: etcd.   See here for tutorials showing their usage with included sample remote services. 

Other distribution and discovery providers are being considered or worked on.  If you are interested in seeing a particular transport supported for distribution or discovery please open an issue on the iPOPO project.

Remote Services between Python and Java

The Python-Java distribution provider makes it possible to use OSGi Remote Services between Python and Java...on both sides.    This allows Remote Services to be exported from Python, and discovered/imported and consumed in Java, or exported from Java and discovered/imported/consumed from Python.  See here for a sample and tutorial.   These capabilities and the underlying distribution provider will be described in more detail in a subsequent posting.


Tuesday, July 03, 2018

Rest Remote Services with CXF or Jersey

ECF's Photon Release now includes an example of using Karaf with the JaxRS distribution provider.

This distribution provider now fully supports OSGi R7 remote services, including async remote services, using either the Jersey or CXF JaxRS implementations.

This allows service developers to easily use only JAX-RS annotations to define and implement OSGi R7 remote services.

Wednesday, June 20, 2018

ECF Photon supports OSGi R7 Async Services - part 2

In a previous post, I described a usage of OSGi R7's Async Remote Services. This specification makes it easy to define, implement and use non-blocking remote services. ECF's implementation allows the use of pluggable transports...known as distribution providers.

Here's a partial list of distribution providers:

R-OSGi
ECF generic
JMS/ActiveMQ
XML-RPC
Hazelcast
MQTT
Jax-RS Jersey
Jax-RS CXF
JavaGroups
Python.Java (Supports async remote services between Java and Python with protocol buffers serialization)

 It's also straightforward to creation your own distribution provider, using private or legacy transport and/or serialization. This can be done by extending one of the distribution providers above or creating a new one.

Most of these distribution providers have updated examples and/or tutorials, and many of them now have templates included in the Bndtools (4.0+) Support added for Photon.

Separating the remote service contract from the underlying distribution provider via OSGi remote services allows implementers and consumers to create, debug, and test remote services without being bound to a single transport, while still allowing consistent (specified) runtime behavior.

For more info and links, please see the New and Noteworthy.

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.