Last active
December 13, 2015 20:08
-
-
Save ericmoritz/4967633 to your computer and use it in GitHub Desktop.
Java vs Erlang.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*~ | |
*.beam |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- -*- mode: html; coding: utf-8 -*- --> | |
After I saw an Java/Appia implementation for the Print module | |
described in [Introduction to Reliable and Secure Distributed | |
Programming](http://www.amazon.com/Introduction-Reliable-Secure-Distributed-Programming/dp/3642152597). | |
I was blown away by all the code that was needed to pass a message to | |
a concurrent actor. I hope that [Akka](http://akka.io/) presents | |
better APIs for doing Actor-based concurrency. | |
## Interface of the printing module | |
<dl> | |
<dt>Module:<dt> | |
<dd>Name: Print.</dd> | |
<dt>Events:</dt> | |
<dd> | |
<dl> | |
<dt>Request</dt> | |
<dd>〈PrintRequest | rqid, str〉: Requests a string to be printed. The token `rqid` is an identifier of the request </dd> | |
<dt>Confirmation</dt> | |
<dd>〈PrintConfirm | rqid〉: Used to confirm that the printing request with identifier `rqid` succeeded</dd> | |
</dl> | |
</dd> | |
</dl> | |
## Algorithim of the printing module | |
<dl> | |
<dt>Implements</dt> | |
<dd>Print.</dd> | |
<dt>upon event 〈PrintRequest | rqid, str〉 do</dt> | |
<dd> | |
<pre><code> | |
print str; | |
trigger 〈PrintConfirm | rqid〉; | |
</code></pre> | |
</dd> | |
</dl> | |
## Java/Appia implementation | |
So without further ado, here's the Java code with the Erlang code. | |
To implement the algorithm described in the pseudo-code presented above. First you need to implement the Event classes: | |
* [PrintRequestEvent](#file-printrequestevent-java) | |
* [PrintConfirmEvent](#file-printconfirmevent-java) | |
Then you need to create a Layer class that describes the Events the module has: [PrintLayer](#file-printlayer-java) | |
Then you actually get to build the event handlers in a Session class [PrintSession](#file-printsession-java) | |
## Simple Erlang implementation | |
I'm not even going to introduce this: | |
```erlang | |
-module(simple_print). | |
%%%% | |
%% Public API | |
%%%% | |
-export([ | |
start/0, | |
print/2 | |
]). | |
start() -> | |
spawn(fun print_process/0). | |
print(Pid, Str) -> | |
From = self(), | |
Rqid = make_ref(), | |
% directly from the interface spec: | |
Request = {print_request, Rqid, Str}, | |
% Send the message | |
Pid ! {From, Request}, | |
% wait for the print_confirm message | |
receive | |
{print_confirm, Rqid} -> | |
ok | |
end. | |
%%%% | |
%% Private | |
%%%% | |
print_process() -> | |
% wait for print_request messages | |
receive | |
{From, {print_request, RqId, Str}} -> | |
io:format("[Print] ~s~n", [Str]), | |
From ! {print_confirm, RqId} | |
end, | |
% loop after handling a request | |
print_process(). | |
``` | |
## gen_server implementation | |
This request/response loop as been abstracted away in OTP's `gen_server` behaviour. Here's the OTP gen_server version of the previous | |
example: | |
```erlang | |
-module(print_server). | |
-behaviour(gen_server). | |
%% Public API | |
-export([start/0, print/2]). | |
%% gen_server callbacks | |
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, | |
terminate/2, code_change/3]). | |
%%%% | |
%% Public API | |
%%%% | |
%% starts the server | |
start() -> | |
gen_server:start(?MODULE, [], []). | |
%% prints a string | |
print(Pid, Str) -> | |
%% gen_server:call handles the rqid for us, we just send the message | |
gen_server:call(Pid, {print_request, Str}). | |
%%%% | |
%% gen_server callbacks | |
%%%% | |
init([]) -> | |
{ok, undefined}. | |
handle_call({print_request, Str}, _From, State) -> | |
io:format("[Print] ~s~n", [Str]), | |
{reply, ok, State}. | |
handle_cast(_Msg, State) -> | |
{noreply, State}. | |
handle_info(_Info, State) -> | |
{noreply, State}. | |
terminate(_Reason, _State) -> | |
ok. | |
code_change(_OldVsn, State, _Extra) -> | |
{ok, State}. | |
``` | |
12 text files. | |
## Cloc | |
``` | |
http://cloc.sourceforge.net v 1.56 T=0.5 s (10.0 files/s, 628.0 lines/s) | |
------------------------------------------------------------------------------- | |
Language files blank comment code | |
------------------------------------------------------------------------------- | |
Java 4 32 154 88 | |
simple_print.erl 1 6 11 23 | |
print_server.erl 1 14 11 22 | |
------------------------------------------------------------------------------- | |
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(print_server). | |
-behaviour(gen_server). | |
%% Public API | |
-export([start/0, print/2]). | |
%% gen_server callbacks | |
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, | |
terminate/2, code_change/3]). | |
%%%% | |
%% Public API | |
%%%% | |
%% starts the server | |
start() -> | |
gen_server:start(?MODULE, [], []). | |
%% prints a string | |
print(Pid, Str) -> | |
%% gen_server:call handles the rqid for us, we just send the message | |
gen_server:call(Pid, {print_request, Str}). | |
%%%% | |
%% gen_server callbacks | |
%%%% | |
init([]) -> | |
{ok, undefined}. | |
handle_call({print_request, Str}, _From, State) -> | |
io:format("[Print] ~s~n", [Str]), | |
{reply, ok, State}. | |
handle_cast(_Msg, State) -> | |
{noreply, State}. | |
handle_info(_Info, State) -> | |
{noreply, State}. | |
terminate(_Reason, _State) -> | |
ok. | |
code_change(_OldVsn, State, _Extra) -> | |
{ok, State}. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Hands-On code of the book Introduction to Reliable Distributed Programming | |
* by Christian Cachin, Rachid Guerraoui and Luis Rodrigues | |
* Copyright (C) 2005-2011 Luis Rodrigues | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | |
* | |
* Contact | |
* Address: | |
* Rua Alves Redol 9, Office 605 | |
* 1000-029 Lisboa | |
* PORTUGAL | |
* Email: | |
* [email protected] | |
* Web: | |
* http://homepages.gsd.inesc-id.pt/~ler/ | |
* | |
*/ | |
package irdp.protocols.tutorialDA.print; | |
import net.sf.appia.core.Event; | |
/** | |
* Print request confirmation event. | |
* | |
* @author alexp | |
*/ | |
public class PrintConfirmEvent extends Event { | |
int rqid; | |
void setId(int rid) { | |
rqid = rid; | |
} | |
int getId() { | |
return rqid; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Hands-On code of the book Introduction to Reliable Distributed Programming | |
* by Christian Cachin, Rachid Guerraoui and Luis Rodrigues | |
* Copyright (C) 2005-2011 Luis Rodrigues | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | |
* | |
* Contact | |
* Address: | |
* Rua Alves Redol 9, Office 605 | |
* 1000-029 Lisboa | |
* PORTUGAL | |
* Email: | |
* [email protected] | |
* Web: | |
* http://homepages.gsd.inesc-id.pt/~ler/ | |
* | |
*/ | |
package irdp.protocols.tutorialDA.print; | |
import net.sf.appia.core.Layer; | |
import net.sf.appia.core.Session; | |
import net.sf.appia.core.events.channel.ChannelInit; | |
/** | |
* Layer of the Print protocol. | |
* @author alexp | |
*/ | |
public class PrintLayer extends Layer { | |
public PrintLayer() { | |
/* events that the protocol will create */ | |
evProvide = new Class[1]; | |
evProvide[0] = PrintConfirmEvent.class; | |
/* | |
* events that the protocol requires to work This is a subset of the | |
* accepted events. | |
*/ | |
evRequire = new Class[0]; | |
/* events that the protocol will accept */ | |
evAccept = new Class[2]; | |
evAccept[0] = PrintRequestEvent.class; | |
evAccept[1] = ChannelInit.class; | |
} | |
public Session createSession() { | |
return new PrintSession(this); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Hands-On code of the book Introduction to Reliable Distributed Programming | |
* by Christian Cachin, Rachid Guerraoui and Luis Rodrigues | |
* Copyright (C) 2005-2011 Luis Rodrigues | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | |
* | |
* Contact | |
* Address: | |
* Rua Alves Redol 9, Office 605 | |
* 1000-029 Lisboa | |
* PORTUGAL | |
* Email: | |
* [email protected] | |
* Web: | |
* http://homepages.gsd.inesc-id.pt/~ler/ | |
* | |
*/ | |
package irdp.protocols.tutorialDA.print; | |
import net.sf.appia.core.Event; | |
/** | |
* Print request event. | |
* | |
* @author alexp | |
*/ | |
public class PrintRequestEvent extends Event { | |
int rqid; | |
String str; | |
void setId(int rid) { | |
rqid = rid; | |
} | |
void setString(String s) { | |
str = s; | |
} | |
int getId() { | |
return rqid; | |
} | |
String getString() { | |
return str; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* Hands-On code of the book Introduction to Reliable Distributed Programming | |
* by Christian Cachin, Rachid Guerraoui and Luis Rodrigues | |
* Copyright (C) 2005-2011 Luis Rodrigues | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this library; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | |
* | |
* Contact | |
* Address: | |
* Rua Alves Redol 9, Office 605 | |
* 1000-029 Lisboa | |
* PORTUGAL | |
* Email: | |
* [email protected] | |
* Web: | |
* http://homepages.gsd.inesc-id.pt/~ler/ | |
* | |
*/ | |
package irdp.protocols.tutorialDA.print; | |
import net.sf.appia.core.AppiaEventException; | |
import net.sf.appia.core.Direction; | |
import net.sf.appia.core.Event; | |
import net.sf.appia.core.Layer; | |
import net.sf.appia.core.Session; | |
import net.sf.appia.core.events.channel.ChannelInit; | |
/** | |
* Session implementing the Print protocol. | |
* <br> | |
* Receives print requests and prints them on screen. | |
* | |
* @author alexp | |
*/ | |
public class PrintSession extends Session { | |
public PrintSession(Layer layer) { | |
super(layer); | |
} | |
public void handle(Event event) { | |
if (event instanceof ChannelInit) | |
handleChannelInit((ChannelInit) event); | |
else if (event instanceof PrintRequestEvent) { | |
handlePrintRequest((PrintRequestEvent) event); | |
} | |
} | |
private void handleChannelInit(ChannelInit init) { | |
try { | |
init.go(); | |
} catch (AppiaEventException e) { | |
e.printStackTrace(); | |
} | |
} | |
private void handlePrintRequest(PrintRequestEvent request) { | |
try { | |
PrintConfirmEvent ack = new PrintConfirmEvent(); | |
System.out.println(); | |
System.out.println("[Print] " + request.getString()); | |
request.go(); | |
ack.setChannel(request.getChannel()); // set the Appia channel where the | |
// event will travel | |
ack.setDir(Direction.UP); // set events direction | |
ack.setSourceSession(this); // set the session that created the event | |
ack.setId(request.getId()); // set the request ID | |
// initializes the event, defining all internal structures, | |
// for instance the path the event will take (sessions to visit) | |
ack.init(); | |
ack.go(); // send the event | |
} catch (AppiaEventException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(simple_print). | |
%%%% | |
%% Public API | |
%%%% | |
-export([ | |
start/0, | |
print/2 | |
]). | |
start() -> | |
spawn(fun print_process/0). | |
print(Pid, Str) -> | |
From = self(), | |
Rqid = make_ref(), | |
% directly from the interface spec: | |
Request = {print_request, Rqid, Str}, | |
% Send the message | |
Pid ! {From, Request}, | |
% wait for the print_confirm message | |
receive | |
{print_confirm, Rqid} -> | |
ok | |
end. | |
%%%% | |
%% Private | |
%%%% | |
print_process() -> | |
% wait for print_request messages | |
receive | |
{From, {print_request, RqId, Str}} -> | |
io:format("[Print] ~s~n", [Str]), | |
From ! {print_confirm, RqId} | |
end, | |
% loop after handling a request | |
print_process(). | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment