@venuur thanks for following along. It’s kind of a scary place to be but its also kind of fun! I am really brushing up on some concepts that were dormont in my brain for a while.
So I made a minimum viable example that requires JeroMQ to be built with maven(don’t run the tests trust me its fine and it’ll save you a half hour), and linked to the JAVA project(https://github.com/zeromq/jeromq/releases/tag/v0.5.1). Also need the ZMQ package to be installed in Julia! What its doing…
- Java calls a Julia program to be run in the background
- Java and Julia exchange a classic syn-ack-synack handshake (useful for debugging)
- Java zmq’s to julia the julia function it wants to use
- Julia evaluates the java instruction, applies it to a float64, then sends it back to java.
- Java converts the number from little endian to big endian then displays it.
- They both close the connections and the world is at peace
import org.zeromq.ZMQ;
import org.zeromq.ZContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ZMQBareBones {
Process juliaServer;
BufferedReader stdInput;
BufferedReader stdError;
public static void main(String[] args) throws Exception {
ZMQBareBones zmqApp = new ZMQBareBones();
zmqApp.run();
}
public void run() throws Exception {
String s = null;
try {
juliaServer = Runtime.getRuntime().exec("julia /home/caseykneale/Desktop/whater.jl");
stdInput = new BufferedReader(new InputStreamReader(juliaServer.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(juliaServer.getErrorStream()));
// read the output from the Julia console directly into java!
//Currently not working needs a loop/wait/cancel routine but whatever the concept does work.
System.out.println("Communication Log:\n");
if ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("Beginning ZMQ:\n");
try (ZContext context = new ZContext()) {
// Socket to talk to clients
ZMQ.Socket socket = context.createSocket(ZMQ.REP);
socket.bind("tcp://*:5555");
boolean handshake = false;
double result = Double.NaN;
while ( (!Thread.currentThread().isInterrupted()) ) {
// Block until a message is received
byte[] reply = socket.recv(0);
if(handshake == false) {
String replymsg = new String(reply, ZMQ.CHARSET);
if (replymsg.equals("SYN")) {
System.out.println("Received: Communication from Julia Client.");
String response = "ACK";
socket.send(response.getBytes(ZMQ.CHARSET), 0);
}
if (replymsg.equals("SYNACK")) {
System.out.println("ZMQ Handshake completed!");
handshake = true;
socket.setReceiveBufferSize(8);
System.out.println("Sending fn to Julia for evaluation...");
//Now that we know we have communication back and forth... let's do something dastardly...
socket.send("exp_decay".getBytes(ZMQ.CHARSET), 0);
//socket.send("reciprocal".getBytes(ZMQ.CHARSET), 0);
}
} else {
System.out.println(reply.length);
//Java likes big endian, Julia likes little endian - such is life...
result = ByteBuffer.wrap(reply).order(ByteOrder.LITTLE_ENDIAN).getDouble();
System.out.println("Computed result: ");
System.out.println(result);
}
}
}
//Close Julia server
juliaServer.destroy();
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
println("Execution of Julia code successful.\n Starting compute client...")
#define some inhouse fns for our "library"
exp_decay(x) = exp(-x)
reciprocal(x) = 1 / x
using ZMQ
client_socket = Socket(REQ)
connect(client_socket, "tcp://localhost:5555")
send(client_socket, "SYN")
msgback = recv(client_socket, String)
if ( msgback == "ACK" )
send(client_socket, "SYNACK")
end
awesomest_data_ever = 111.111
#get the Java user's desired function call
function_call = recv(client_socket, String)
result = eval( Meta.parse("$function_call($awesomest_data_ever)") )
#pass back the result as a Float64
send(client_socket, result)
#we're done here...
close(client_socket)
What I’m wondering now is - is it easier to just use a BufferedWriter to write to a background Julia REPL or something? Not sure…
Also the pattern of a massive ZMQ loop is pretty impractical for an interactive application. Might need to see how other people are doing this. My guess is they have listeners polling 24/7 and they drop in and drop out of the server context regularly.