Skip to content

Instantly share code, notes, and snippets.

@ericmoritz
Last active December 13, 2015 20:08
Show Gist options
  • Save ericmoritz/4967633 to your computer and use it in GitHub Desktop.
Save ericmoritz/4967633 to your computer and use it in GitHub Desktop.
Java vs Erlang.
<!-- -*- 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
-------------------------------------------------------------------------------
```
-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}.
/*
*
* 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:
* ler@ist.utl.pt
* 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;
}
}
/*
*
* 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:
* ler@ist.utl.pt
* 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);
}
}
/*
*
* 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:
* ler@ist.utl.pt
* 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;
}
}
/*
*
* 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:
* ler@ist.utl.pt
* 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();
}
}
}
-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