Vert.X RIFA - Rich Interfaces For Actors

Utility library for Vert.X that allows using strong-typed interfaces in communication through EventBus


Vert.X RIFA - Rich Interfaces For Actors

This library introduces concept of asynchronous object-oriented programming ‘by contract’ in Vert.X.
Usually if you want to send message in Vert.X from one Actor(Verticle) to other you need to use eventBus.send or eventBus.publish with some object as payload. Objects should be some sort of simple types like String,Integer or special objects like JsonObject. Of course you can register own codec and send anything you want but type checking on receiving side is a developer responsibility. You should also write boilerplate for message handlers and handler registering.
VxRifa library implements Java-idiomatic style for actors messaging based on Interfaces.

Getting started

If you are using Maven or Gradle, add the following dependency to the dependencies section of your project descriptor to access the VxRifa:
Maven (in your pom.xml):

<dependency>
  <groupId>io.github.nsforth</groupId>
  <artifactId>vxrifa</artifactId>
  <version>1.4.3</version>
</dependency>

Gradle (in your gradle build.xml):

dependencies {
  compile 'io.github.nsforth:vxrifa:1.4.3'
}

Any interface can be annotated with @VxRifa. Methods should return one of void, io.vertx.core.Future, io.vertx.core.streams.ReadStream, io.vertx.core.streams.WriteStream. Whenever java compiler processes annotations (when building project or on the fly in modern IDEs) VxRifa generates special classes that do all work. You can see generated code under target/generated-sources with maven or under build directory with gradle. For example:

@VxRifa
public interface Calculator {
 
    Future<Double> sumTwoDoubles(Double one, Double two);
  
    void reset();

}

Implementation in Verticle that exporting such API would look like that:

public class CalculatorImpl implements Calculator {
 
    @Override
    public Future<Double> sumTwoDoubles(Double one, Double two) {
        Future<Double> future = Future.future();
        future.complete(one + two);
        return future;
    }
   
    @Override
    public void reset() {
          
        // Some reset actions 
 
    }

}

Now you can get instance of VxRifaReceiver with VxRifaUtil.getReceiverRegistrator which creates any needed eventBus.consumer’s and calls methods of Calculator whenever it receives messages from other actors.
Other Verticles should use VxRifaUtil.getSenderByInterface that returns VxRifa-driven implementation of Calculator which send messages under the hood. For example:

.... CalculatorVerticle ....

Calculator calc_impl = new CalculatorImpl();
VxRifaReceiver<Calculator> registrator = VxRifaUtil.getReceiverRegistrator(vertx, Calculator.class);
Future<?> when_registered = registrator.registerReceiver(calc_impl);
 
.... Some other verticles that wants to use Calculator API ....

Calculator calc = VxRifaUtil.getSenderByInterface(vertx, Calculator.class);
calc.sumTwoDoubles(1.0, 2.0).setHandler(result -> {
    if (result.succeeded()) {
        Double sum = result.result();
    }
});

Publish/Subscribe scheme

It is possible to send broadcast messages for multiple instances of some interface annotated with @VxRifaPublish. It’s one way communication of course so methods can’t return anything but void. You should use VxRifaUtil.getPublisherByInterface to get instance of publisher for @VxRifaPublish subscribers.

Streams support

Interfaces annotated with @VxRifa can have methods returning two types of streams: ReadStream and WriteStream. VxRifa wraps your streams and push your data through Vert.X eventbus automatically. Stream is not immediately ready after invoking on sender side method with Stream return types and you should properly connect it to your handlers. For example, you should set drainHandler for WriteStream. For ReadStream it should be handler and endHandler.

Notes and limitations

There is one small thing that should be done before using VxRifa. You must call VxRifaUtil.registerRIFACodec once for any instance of Vert.x. VxRifa uses wrapper as container for methods parameters so that wrapper should be registered before any sending by eventBus.
You should also remember that any parameters and returned objects should be immutable(effectively immutable) or at least thread-safe. Currently messaging by VxRifa only possible for local non-clustered Vert.X instances because RIFAMessageCodec not supported network encoding/decoding of objects. I hope to solve that in near future.

Supported Vert.x and Java versions

Starting from VxRifa 1.4.0 Java 8 is not supported anymore. Vert.X minimum supported version is 3.9 You can use 1.3.1 and previous versions with Java 8 and Vert.x 3.6