Communication b/w Java (Maven) and Erlang (rebar3) using Jinterface
Tags: jinterface, java, erlang, epmd
Published: 2023-08-26 23:40:01

---
title: Communication b/w Java (Maven) and Erlang (rebar3) using Jinterface
published: true
date: 2023-08-26 09:38:06 UTC
tags: Jinterface, java, erlang, epmd
canonical_url: https://shubham.codes/blog/2023-08-22-jinterface-erlang/
---

## Introduction

`Jinterface` is a way to make `Java` programs behave like `Erlang` nodes. This ensures seamless communication between `Erlang` and `Java` programs.`Jinterface` exposes some APIs that you can use to create `Erlang` data structures and send them to `Erlang` nodes.

## How to use Jinterface

### Installation

For using `Jinterface` you need a `jar` file provided by `Erlang` called `OtpErlang.jar`. You can find the location of the `jar` by opening `erlang` shell and typing the below command. This will provide you with the location of the jar file.

```
> code:priv_dir(jinterface).
"/usr/local/lib/erlang/lib/jinterface-1.13.2/priv"


$ ls "/usr/local/lib/erlang/lib/jinterface-1.13.2/priv"
OtpErlang.jar

```

It may happen that the file isn't there. This is because `Jinterface` is not installed by default. In this case, you will need to install `Erlang` from the source with `Java 8+` installed on the path.

> If you have installed `Erlang` using `homebrew` on _macOS_ then it might not be there.

So first make sure, you have `Java` runtime installed. If not, then please install this first.

```
$ java -version
openjdk version "20.0.1" 2023-04-18
OpenJDK Runtime Environment (build 20.0.1+9-29)
OpenJDK 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing)

```

Remove your old installation of `Erlang` if you have any. Then clone the `Erlang` repository and build it from the source.

```
$ git clone https://github.com/erlang/otp.git
$ cd otp
$ git checkout maint-25
$ ./configure && make && make install

```

Also, verify if the jar has been installed correctly as we did earlier.

### Creating a Java node

#### New Maven Project

Let's first create a new `maven` project.

```
$ mvn archetype:generate -DgroupId=com.example \
    -DartifactId=myproject \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DinteractiveMode=false

```

And you might also want to update the `Java` version and `encoding` by adding/updating the below properties in `pom.xml`.

```
<properties>
    <maven.compiler.source>20</maven.compiler.source>
    <maven.compiler.target>20</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

```

#### Adding Jinterface dependency

The easiest way is to install your `jar` in `m2` and add it to your dependency.

```
$ mvn install:install-file \
   -Dfile=/usr/local/lib/erlang/lib/jinterface-1.13.2/priv/OtpErlang.jar \
   -DgroupId=com.ericsson.otp \
   -DartifactId=erlang \
   -Dversion=1.13.2 \
   -Dpackaging=jar \
   -DgeneratePom=true

```

And then add the dependency in `pom.xml`.

```
<dependency>
    <groupId>com.ericsson.otp</groupId>
    <artifactId>erlang</artifactId>
    <version>1.13.2</version>
</dependency>

```

#### Creating a Java node

This is the fun part. Each `Java` app will contain a node and a mailbox. We can send the message to the node on a particular mailbox and the node will receive the message and process it exactly like `Erlang` nodes.

But first, import the required packages.

```
import com.ericsson.otp.erlang.*;

```

Let's create a node called, 'java\_node' and a mailbox called, 'java\_mailbox'.

```
OtpNode node = new OtpNode("java_node");
OtpMbox mbox = node.createMbox("java_mailbox");

```

Next, let's say we will be sending the node a tuple containing the `Pid` of the Erlang node and a message atom called `hello`. On receiving `{Pid, hello}` as the message, we will send 'world' as a message to the calling node.

The `mbox.receive()` function will pause the execution of the program until it receives a message. We are typecasting the received message to `OtpErlangTuple` because we know that the message will be a tuple and let's extract the `Pid` and the message atom from the tuple.

```
// Get the message
OtpErlangTuple erlTuple = (OtpErlangTuple) mbox.receive();

// Parse the message
OtpErlangPid fromPid = (OtpErlangPid) erlTuple.elementAt(0);
OtpErlangAtom atom = (OtpErlangAtom) erlTuple.elementAt(1);

```

Now we will check if the message is `hello` and if that is the case, we will send `world` as a message to the calling node. Messages can be sent using the `mbox.send()` function.

```
if (atom.atomValue().equals("hello")) {
    // Create the reply message
    OtpErlangAtom replyAtom = new OtpErlangAtom("world");
    OtpErlangObject[] replyElements = {new OtpErlangAtom("ok"), replyAtom};
    OtpErlangTuple replyTuple = new OtpErlangTuple(replyElements);
    
    // This will send the message to the calling node with Pid as fromPid
    mbox.send(fromPid, replyTuple);
}

```

#### Alive function

You might want to create a health checker function to get a reply on pinging the node. This is done by creating a `isAlive` function and it comes in handy while debugging and in code as a sanity check.

```
public boolean isAlive() {
        return true;
    }

```

#### Final Java code

Your final `Java` code will look something like this.

```
package com.example;

import com.ericsson.otp.erlang.*;

public class HelloWorld {
    public boolean isAlive() {
            return true;
        }

    public static void main(String[] args) throws Exception {
         OtpNode node = new OtpNode("java_node");
         OtpMbox mbox = node.createMbox("java_mailbox");
         System.out.println("Node Created. Now, you can communicate with this node.");
         OtpErlangTuple erlTuple = (OtpErlangTuple) mbox.receive();
         OtpErlangPid fromPid = (OtpErlangPid) erlTuple.elementAt(0);
         OtpErlangAtom atom = (OtpErlangAtom) erlTuple.elementAt(1);
         if (atom.atomValue().equals("hello")) {
             OtpErlangAtom replyAtom = new OtpErlangAtom("world");
             OtpErlangObject[] replyElements = {new OtpErlangAtom("ok"), replyAtom};
             OtpErlangTuple replyTuple = new OtpErlangTuple(replyElements);
             mbox.send(fromPid, replyTuple);
         }
    }
}

```

You can verify if your `Java` app is being registered as a node using the below commands in the `Erlang` shell. As we have implemented the `isAlive` function, we can also `ping` the node. A return value of `pong` means success and `pang` means failure.

```
$ erl -sname client
> net_adm:names().
{ok,[{"java_node",59873}]}

> net_adm:ping(java_node@GGN002262).       
pong

```

### Erlang Node

#### Erlang program

On the `Erlang` side we can just send the message to the `java_node` and wait for a message.

> The `GGN002262` part of my node is my hostname. Use the `hostname` command to get yours.

```
-module(client).
-export([start/0]).

start() ->
  {java_mailbox, 'java_node@GGN002262'} ! {self(), hello},
  receive

  {ok, Res} ->
     io:format("Java says: ~p~n", [Res])
  end.

```

#### Run a distributed service

You will need to start the `Erlang` runtime as a distributed service. This can be done using `-sname` flag.

```
$ erl -sname client
1> c(client).
2> client:start().
Java says: world

```

## Starting EPMD

`epmd` program comes prepacked with the `Erlang` distribution. This is the `Erlang` port manager. This is required for registering nodes.

If `epmd` is not running then you will get an error something like this, `Nameserver not responding on GGN002262 when publishing java_node`.

To start the `epmd` server, you just need to run `epmd` from your shell.

```
# Start epmd server in the background
$ epmd&

# Run the Java app
> java -jar my-app.jar

# Verify if the app is getting registered.
$ epmd -names
epmd: up and running on port 4369 with data:
name java_node at port 59873

```

If your `Java` app is registered, you will get the above output.

## Conclusion

Here, we discussed how to use `Jinterface` to communicate with `Erlang` using `Java`. We saw that `Java` programs can behave as `Erlang` nodes and can communicate with each other through message passing. We also learned about `epmd`, the Erlang port manager.

One thing to consider while using `Jinterface` is it simulates the `Java` node as an `Erlang` node, which makes the communication a little bit slow hence this approach should not be taken for a system that requires high-frequency message transfer.

It is also important to note that by default, this process of message transfer is `async` which means we will need to wait for `Java` to process the result and send a message back. There are ways to make this `synchronous` by creating a mechanism to send a confirmation message from the client side on receiving the processed message.

Overall, this is a great add-on to `Erlang` that pumps the power of `Java` into `Erlang's` world.