My Profile Photo

Nithin Krishna


The art challenges the technology, and the technology inspires the art. - John Lasseter


Generic Server in Erlang

NOTE: There is no introduction here

gen_server:start_link({local, module},module,[],[]).

We can start the generic server with the call start_link which generally takes four arguments. The First argument specifies the name(here name is locally registered, it can also be globally registered).The second argument is the Module in which the callback fuctions reside. Fourth function is for the callback function init/1. Fifth argument is the list of options. That is

Argument 1: Name of the generic server.

Argument 2: Name of call back Module.

Argument 3: Call back function init.

Argument 4: List of Options.

We can go through this concept with the help of a example. This example is of a Simple library(lib Module which has function interfaces) and corresponding generic server(gs Module). Here through the functional interfaces simple actions like view all the available books, lookup a book, checkout a book are possible.

Functional Interfaces


-module(lib).


-export([start/0, lookup/1, add/1, checkout/1, record/0]).

start()->
    gen_server:start_link({local, ?MODULE}, gs, [], []).



lookup(Book)->
    {reply, Availabilty} = gen_server:call(?MODULE, {lookup, Book}),
     Availabilty.

checkout(Book)->
   {reply,Msg,_Books} = gen_server:call(?MODULE, {checkout, Book}),
   io:format("~w~n",[Msg]).

record()->
   [{Available, CheckedOut}] = gen_server:call(?MODULE, available_books),
   io:format("Available : ~w~n",[Available]),
   io:format("Checked Out : ~w~n",[CheckedOut]).
   
   

Callback Module


-module(gs).
-behaviour(gen_server).

-export([handle_info/2,terminate/2,code_change/3]).

-export([handle_call/3,handle_cast/2,lookup/2,record/1,checkout/2,init/1]).

init(_Args)->
    {ok, {all_books(), []}}.



%%Hard coded

all_books() -> [mobydick, troy, tempest]].

%%call_backs

handle_call({lookup, Book}, _From, Books)->
      Availability = lookup(Books, Book),
      {reply, Availability, Books};

handle_call(available_books, _From, Books) ->
    AllBooks = record(Books),
    {reply, AllBooks, Books};

handle_call({checkout, Book}, _From, Books) ->
    {reply,Msg, FreeBooks} = checkout(Books, Book),
    {reply,{reply,Msg, FreeBooks}, FreeBooks}.







%%Internals

lookup({Avbl_Books, _CheckedOut }, Book)->
    case lists:member(Book, Avbl_Books) of
	true -> {reply, available};
	false -> {reply, not_available}
    end.

record(Books)->
    [Books].

checkout({Avbl_Books, CheckedOut}, Book)->
    case lists:member(Book,Avbl_Books) of
     true ->
            Free_Books = lists:delete(Book, Avbl_Books),
	    {reply, book_checked_out, {Free_Books, [Book|CheckedOut] }};
     false ->
           case lists:member(Book, CheckedOut) of
           
              true -> 
		   {reply,book_already_checked_out,{Avbl_Books, CheckedOut}};
      	      false ->
                   {reply,book_not_in_lib,{Avbl_Books, CheckedOut}}

           end
    end.
	
handle_cast(_request, _State)->
    ok.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.