My eyes snap open. The room is dark and the wind, who has sauntered into my room finding a new home, is flapping the blackout curtains wildly. A cold chill is running down my spine. I had a dream, an Android that learned alchemy. I must teach it how to mix
potions. How to share its cookies with Elixir. There is work to be done.
Before we get excited and attempt to do this all from Android, lets see how much of this we can test with locally.
To get started, we’ll build an addition calculator that only accepts x + y
. A simple GenServer[1] will work wonderfully for our example. Plugging this into a mix
project and a Supervisor
to register its name locally as :calculator
is quite easy[2].
defmodule JavaTest.Calculator do
@moduledoc """
A simple, simple calculator.
"""
use GenServer
def start_link(opts) do
{} = GenServer.start_link(__MODULE__, :ok, opts)
{:ok, pid}
end
def init(:ok) do
{:ok, %{}}
end
def handle_call({:add, lvalue, rvalue}, _from, state) do
IO.puts "#{lvalue + rvalue}"
{:reply, lvalue + rvalue, state}
end
end
To breath life into it, sit cross-legged with index finger tips touching pinky finger tips. Repeat after me
iex --sname liu-kang --erl "-setcookie test-cookie" -S mix run
Some explination of the incantation:
--sname
: is the name of our node.--erl
: setting things up in the way of our ancestors.-setcookie test-cookie
: insecure, but each of our code needs have this anchor pont.Next we must brew some Java to mix
with our Elixr before we assemble our Android.
Our two languages are distant, their ways of life are incompatble. The JInterface
[3], provided in our erlang installation is the hermit who’ll play translator. Mine resided quitetly and full of exceitement, waiting to be utilized in /usr/lib/erlang/lib/jinterface-1.9/priv
. Yours is waiting too, just as quietly but equally as excited.
import com.ericsson.opt.erlang.*
Is how we’ll summon our little hermit.
There are two known paths that we can take. But only one is correct going forward.
We can attempt to use the epdm
and rpc
calls as the channel of communication, but I am unsure if we can bring this into the strange, distant lands we are going with Android.
So we must use the mail boxes to do our communication.
What we first need to do is create an erlang node, set its cookie, then create a mailbox for it.
public class JavaElixirSender {
private final String ELIXIR_NAME = "liu-kang@warriorShrine";
private final String NODE_NAME = "goro";
private final String MBOX_NAME = "goro-mailbox";
private final String COOKIE = "test-cookie";
private final String PROCESS_NAME = "calculator";
static void start() throws IOException,
OtpAuthException,
InterruptedException {
OtpNode node = new OtpNode(NODE_NAME);
node.setCookie(COOKIE);
OtpMbox mailBox = node.createMbox(MBOX_NAME);
}
public static void main (String [] args) throws
IOException,
OtpAuthException,
InterruptedException {
start();
}
}
Here is our desired message format to send to our GenServer. While in Elixir, we can simply call this from the remote console, when registering the process name as :calculator
:
GenServer.call(:calculator, {:add, 1, 2})
We must imagine what this looks like, in its most primordial state:
{'$gen_call', {self(), make_ref()}, {:add, 1, 2}}
We must not be afraid to craft this in Java. We have the tools and the materials[4]
OtpErlangObject[] tag = new OtpErlangObject[2];
tag[0] = mailBox.self();
tag[1] = node.createRef();
OtpErlangObject[] data = new OtpErlangObject[3];
data[0] = new OtpErlangAtom("add");
data[1] = new OtpErlangInt(1);
data[2] = new OtpErlangInt(2);
OtpErlangObject[] body = new OtpErlangObject[3];
message[0] = new OtpErlangAtom("$gen_call");
message[1] = new OtpErlangTuple(tag);
message[2] = new OtpErlangTuple(data);
OtpErlangTuple message = new OtpErlangTuple(body);
We have provided all that is needed. Now, lets see if these two deamons would like to speak:
mailBox.send(PROC_NAME, ELIXIR_NODE_NAME, message);
OtpErlangObject response = mailBox.receive(1000);
if(response != null) {
OtpErlangTuple responseTuple = (OtpErlangTuple) response;
System.out.println(responseTuple.elementAt(1).toString());
}
What I hear is harmony between them. The addition is returned. All is well.
Look out for part 2, where I’ll find out if its even possible to continue forward :)
Keep it real,
Matthew