Integrating Erlang and Java Dennis Byrne - ThoughtWorks [email_address] 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 © ThoughtWorks 2008 Both compiled to byte code
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_address] ’  =  node() . OtpNode node = new OtpNode("name@host.com"); assert "name@host.com".equals( node.node() ); © ThoughtWorks 2008
Modeling a Node, Short Name $erl -sname name >  ‘ [email_address] ’  =  node() . OtpNode node = new OtpNode( “ name ” ); assert  “ [email_address] ” .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 © ThoughtWorks 2008
Thanks Dennis Byrne [email_address] http://notdennisbyrne.blogspot.com/ © ThoughtWorks 2008

Integrating Erlang and Java

  • 1.
    Integrating Erlang andJava Dennis Byrne - ThoughtWorks [email_address] http://notdennisbyrne.blogspot.com/ © ThoughtWorks 2008
  • 2.
    Overview Java vs.Erlang Jinterface Intro Erlang Data Types Nodes Message Passing Process Registration Linking Trapping Exits © ThoughtWorks 2008
  • 3.
    Java vs. ErlangStrongly typed Object Oriented Pass by Reference Shared Memory Mutable State Nouns Dynamically Typed Functional Programming Pass by Value Non shared memory Immutable State Verbs © ThoughtWorks 2008 Both compiled to byte code
  • 4.
    Introduction Created inJava 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
  • 5.
    Modeling Erlang TypesOtpErlangObject OtpErlangPid OtpErlangRef OtpErlangList OtpErlangPort OtpErlangBinary OtpErlangBoolean OtpErlangByte OtpErlangTuple OtpErlangString OtpErlangFloat OtpErlangAtom © ThoughtWorks 2008
  • 6.
    Modeling Nodes OneJVM, more than one node Jinterface nodes are “hidden nodes” Hidden Node $ erl –hidden Non-transitive connections Not returned by erlang:nodes/0 © ThoughtWorks 2008
  • 7.
    Modeling a Node,Long Names $ erl – name name > ‘ [email_address] ’ = node() . OtpNode node = new OtpNode("name@host.com"); assert "name@host.com".equals( node.node() ); © ThoughtWorks 2008
  • 8.
    Modeling a Node,Short Name $erl -sname name > ‘ [email_address] ’ = node() . OtpNode node = new OtpNode( “ name ” ); assert “ [email_address] ” .equals( node.node() ); © ThoughtWorks 2008
  • 9.
    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
  • 10.
    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
  • 11.
    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
  • 12.
    Local Status ChangesOtpNode 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
  • 13.
    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
  • 14.
    Handling Connection AttemptsOtpNode node = new OtpNode("a"); node.registerStatusHandler( new OtpNodeStatus() { public void connAttempt(String node, boolean incoming, Object info) { // handle failed connections } }); © ThoughtWorks 2008
  • 15.
    Modeling Processes withOtpMbox $ 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
  • 16.
    receive $ erl> receive Any -> Any after 1000 -> true end. OtpMbox mailBox = node.createMbox(); mailBox.receive(1000); © ThoughtWorks 2008
  • 17.
    Pass By ValueOtpNode 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
  • 18.
    User Defined ClassesOtpMbox 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
  • 19.
    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
  • 20.
    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
  • 21.
    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
  • 22.
    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
  • 23.
    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
  • 24.
    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
  • 25.
    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
  • 26.
    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
  • 27.
    Concurrent Programming FastContext Switching Fast Message Passing Fast Process Spawning © ThoughtWorks 2008
  • 28.
    Synchronization Sending andreceiving messages Mailbox creation Linking and unlinking processes Node creation © ThoughtWorks 2008
  • 29.
    Thanks Dennis Byrne[email_address] http://notdennisbyrne.blogspot.com/ © ThoughtWorks 2008