integrating erlang and java
TRANSCRIPT
© ThoughtWorks 2008
Integrating Erlang and Java
Dennis Byrne - [email protected]
http://notdennisbyrne.blogspot.com/
© ThoughtWorks 2008
Overview
• Java vs. Erlang• Jinterface Intro• Erlang Data Types • Nodes• Message Passing• Process Registration • Linking• Trapping Exits
© ThoughtWorks 2008
Java vs. Erlang
• Strongly typed• Object Oriented• Pass by Reference• Shared Memory• Mutable State• Nouns
• Dynamically Typed• Functional Programming• Pass by Value• Non shared memory• Immutable State• Verbs
Both compiled to byte code
© ThoughtWorks 2008
Introduction
• Created in Java 1.1• Little more than 10,000 LoC• Primarily authored by Gordon Beaton• OTP_DIR\lib\jinterface-X.X\priv\OtpErlang.jar• Jinterface Nodes run in separate user space• Different than JRuby, Jython, Groovy, etc.• Speaks the wire protocol
© ThoughtWorks 2008
Modeling Erlang Types
• OtpErlangObject• OtpErlangPid• OtpErlangRef• OtpErlangList• OtpErlangPort• OtpErlangBinary
• OtpErlangBoolean• OtpErlangByte• OtpErlangTuple• OtpErlangString• OtpErlangFloat• OtpErlangAtom
© ThoughtWorks 2008
Modeling Nodes
• One JVM, more than one node• Jinterface nodes are “hidden nodes”• Hidden Node
– $ erl –hidden– Non-transitive connections– Not returned by erlang:nodes/0
© ThoughtWorks 2008
Modeling a Node, Long Names
$ erl –name name> ‘[email protected]’ = node().
OtpNode node = new OtpNode("[email protected]");
assert "[email protected]".equals(node.node());
© ThoughtWorks 2008
Modeling a Node, Short Name
$erl -sname name
> ‘name@byrned’ = node().
OtpNode node = new OtpNode(“name”);assert “name@byrned”.equals(node.node());
© ThoughtWorks 2008
Cookies, Command Line
$ erl –name name –setcookie cookie> cookie = erlang:get_cookie().
OtpNode node = new OtpNode(“name”, “cookie”);assert "cookie".equals(node.cookie());
© ThoughtWorks 2008
Cookies, Programmatically
$ erl –name name> erlang:set_cookie(node(), cookie)
> cookie = erlang:get_cookie().
OtpNode node = new OtpNode(“name”);node.setCookie("cookie");
assert “cookie”.equals(node.cookie());
© ThoughtWorks 2008
net_adm:ping/0
$ erl> pong = net_adm:ping(b@byrned).> pang = net_adm:ping(c@byrned).
OtpNode a = new OtpNode("a@byrned", "z");OtpNode b = new OtpNode("b@byrned", "z");OtpNode c = new OtpNode("c@byrned", "notz");assert a.ping("b", 20);assert !a.ping("c", 20) & !a.ping("d", 20);
© ThoughtWorks 2008
Local Status Changes
OtpNode node = new OtpNode(“node”);
node.registerStatusHandler( new OtpNodeStatus() { public void localStatus(String node,
boolean up, Object info) {// local initialization // or clean up logic
}});
© ThoughtWorks 2008
Remote Status Changes, monitor_node/2
OtpNode node = new OtpNode(“node”);
node.registerStatusHandler(
new OtpNodeStatus() {
public void remoteStatus(String node, boolean up, Object info) {
// peer node is up or down?
}
});
© ThoughtWorks 2008
Handling Connection Attempts
OtpNode node = new OtpNode("a");
node.registerStatusHandler( new OtpNodeStatus() { public void connAttempt(String node,
boolean incoming, Object info) {// handle failed connections
}});
© ThoughtWorks 2008
Modeling Processes with OtpMbox$ erl –sname foo> Pid = self(), Msg = 999.> spawn( fun() -> Pid ! Msg end ).> Msg = receive Any -> Any end.
OtpNode node = new OtpNode("foo");OtpMbox first = node.createMbox();OtpMbox second = node.createMbox();OtpErlangInt msg = new OtpErlangInt(999);second.send(first.self(), msg);assert msg.equals(first.receive());
© ThoughtWorks 2008
receive
$ erl
> receive Any -> Any after 1000 -> true end.
OtpMbox mailBox = node.createMbox();
mailBox.receive(1000);
© ThoughtWorks 2008
Pass By Value
OtpNode node = new OtpNode("value");OtpMbox from = node.createMbox();OtpMbox to = node.createMbox();OtpErlangLong sent = new OtpErlangLong(9);from.send(to.self(), sent);Object received = to.receive();
assert sent != received;
© ThoughtWorks 2008
User Defined Classes
OtpMbox to = node.createMbox();OtpMbox from = node.createMbox();Customer customer = new Customer();customer.name = "Dennis";
from.send(to.self(), new OtpErlangBinary(customer));
OtpErlangBinary bin = (OtpErlangBinary) to.receive();Customer object = (Customer)bin.getObject();assert "Dennis".equals(object.name);
© ThoughtWorks 2008
Remote Execution
OtpErlangObject[] call = new OtpErlangObject[] {new OtpErlangAtom("call"),new OtpErlangAtom("erlang"), /* mod */new OtpErlangAtom("node"), /* fun */new OtpErlangList(), /* arg */new OtpErlangAtom("user")
};OtpErlangTuple msg = new OtpErlangTuple( new OtpErlangObject[] {
mailBox.self(), new OtpErlangTuple(call)
});
© ThoughtWorks 2008
Remote Execution
mailBox.send("rex", "d@byrned", msg);
OtpErlangTuple response =
(OtpErlangTuple) mailBox.receive();
OtpErlangObject proc = response.elementAt(0);
assert "rex".equals(proc.toString());
OtpErlangObject from = response.elementAt(1);
assert "d@byrned".equals(from.toString());
© ThoughtWorks 2008
register/2$ erl> register(first, self()).> Msg = 999.> spawn(fun() -> first ! Msg end). Msg = receive Any -> Any end.
OtpMbox first = node.createMbox();OtpMbox second = node.createMbox();OtpErlangInt msg = new OtpErlangInt(999);first.registerName("first");second.send("first", msg);assert msg.equals(first.receive());
© ThoughtWorks 2008
whereis/2
$ erl
> Pid = self().
> register(w, Pid).
> spawn(fun() -> Pid = whereis(w) end).
OtpNode node = new OtpNode(“whereis”);OtpMbox first = node.createMbox(“w”);OtpMbox second = node.createMbox();
assert first.self() == second.whereis(“w”);
© ThoughtWorks 2008
registered/0> register(a, self()).
> F = fun() -> receive Any -> Any end end.
> register(b, spawn(F)).
> true = lists:member(a, registered()).
> true = lists:member(b, registered()).
OtpNode node = new OtpNode("node");
node.createMbox("a");
node.createMbox("b");
List names = Arrays.asList(node.getNames());
assert names.contains("a");
assert names.contains("b");
© ThoughtWorks 2008
Linking
> process_flag(trap_exit, true).
> F = fun() ->
receive after 200 -> exit(normal) end
end.
> Pid = spawn_link(F).
OtpMbox first = node.createMbox();
OtpMbox second = node.createMbox();
first.link(second.self());
second.close();
© ThoughtWorks 2008
Trapping Exits
{'EXIT', Pid, normal} = receive X -> X end.
try {
first.receive();
}catch(OtpErlangExit e) {
assert second.self().equals(e.pid());
assert "normal".equals(e.getMessage());
}
© ThoughtWorks 2008
Unlinking
> Pid = spawn_link(Fun).
> unlink(Pid).
> nil = receive X -> received
after 2000 -> nil end.
OtpMbox first = node.createMbox();
OtpMbox second = node.createMbox();
first.link(second.self());
second.unlink(first.self());
second.exit("normal");
assert null == first.receive(1);
© ThoughtWorks 2008
Concurrent Programming
• Fast Context Switching• Fast Message Passing• Fast Process Spawning
© ThoughtWorks 2008
Synchronization
• Sending and receiving messages• Mailbox creation • Linking and unlinking processes• Node creation