Grails Testing Acegi Security

Almost every web application I create needs some form of user authentication and authorization. Grails provides a great plugin system that allows you to extend the base framework to provide these kinds of features. My current favorite security plugin for Grails is the Acegi Security Plugin. It’s built using the Spring Security framework and the robust and widely used Acegi framework. I like the fact that it is built on top of existing, well-known frameworks which is the philosophy of Grails itself. It is also a flexible plugin that has a good default object model.

One of the situations that inevitably arises is how to unit test code that depends on your security framework. Either you will want to test that basic authorization is working, or you might have code that makes decisions based upon who is logged in or what roles they might have. To run those test you have to setup your test cases so that the code that works when the system is running normally is tested.

Unit Testing Setup for Testing Acegi Security Code

This situation arose for me the other day and so I thought I would share the solution that I came up with.

import org.springframework.security.context.SecurityContextHolder as SCH
import org.springframework.security.providers.TestingAuthenticationToken
import org.springframework.security.GrantedAuthority
import org.springframework.security.Authentication
import org.springframework.security.GrantedAuthorityImpl
 
class AuthenticationBaseTests extends GroovyTestCase {
def setUp() {
    def user = User.get(1)    // or create a new one if one doesn't exist
    authenticate(user, "abc123", [new GrantedAuthorityImpl('ROLE_ADMIN')])
}
 
protected Authentication authenticate(user, credentials, authorities) {
    def principal = new Expando()
    principal.domainClass = user
 
    Authentication authentication = new TestingAuthenticationToken(principal, null, authorities as GrantedAuthority[])
    authentication.authenticated = true
    SCH.context.authentication = authentication
    return authentication
}
}

setUp()

The setUp() method will get executed prior to your tests being run. So if you want to do different things for each test you would want to move this code to a more appropriate place. In the setup method we are creating our Principle class, in this case, the User. Next we pass the user along with all of the roles we want the user to have for the given test case.

authenticate(user, credentials, authorities)

The real setup work is done in the authenticate() method. This method does the real work of setting up the Authentication Token and setting it in the static context, which is a thread local variable I think, that is used by the framework to determine who is making the request and what rights they have.

The fun thing about this message is the use of the Expando class. Expando allows you to create a class on the fly. This is a really interesting way to do a Mock object on-the-fly in Groovy. In this case we’re creating a Mock authentication principle. We know, by looking at the Acegi Security code, that the security framework expects an object that will call domainClass to get the underlying implementation of the User (or Principle) implemented in the application. That will return us the User object that we are setting.

This simple method can be added to a base class and then inherited from any tests that need user authentication to run successfully.

Posted in Groovy | Tagged , , , , | 4 Comments

Grails Validations Based on Related Objects

Grails has a rich set of tools for performing validations of your domain objects. There are quite a few built in validations that you can use. These mainly resolve around validating single properties within a single domain object. It also supports things like validating the sizes of dependent collections.

Sometimes you need to know about the properties of one instance to validate another dependent instance. The property of that dependent instance might be used to determine the valid values of or might provide a limit for a property.

This is more easily explained with an example.

Problem Statement

I’ll use voting for members of the Board of a public company as an example.

A ShareHolder owns N number of shares of stock in a company. When the ShareHolder votes on a Board member of the company, the ShareHolder can assign 1 to N shares to that Candidate. The top 5 Candidates that receive the most Shares (not individual votes) win the election.

We might create a series of Domain classes like this:

class ShareHolder {
    static hasMany = [votes:Vote]
 
    String name
    Double shares
}
 
class Candidate {
    static hasMany = [votes:Vote]
 
    String name
}
 
class Vote {
    static belongsTo = [shareHolder: ShareHolder, candidate: Candidate]
 
    Double voteShares
}

A ShareHolder can vote multiple times, so it has many Votes. A Candidate can be voted for many times, so it has many Votes. A given Vote can be assigned 1 or more shares. But the shares for a given vote must be less than or equal to the number of shares that the voter (the ShareHolder) owns.

Validation

The natural place to perform this validation is on the Vote domain object itself. The problem is that the limit is really the shares value from the ShareHolder domain object. To solve this we can not use a built in validation. Instead we need to create our own.

To do this we can utilize the validator validation. This is no different than any other custom validation that we might need to create. Since we must have the ShareHolder and the Candidate set for this to be a valid object, we can assume that they are available. Because of this we should be able to access their properties to validate our Vote domain object.

Add a custom validator constraint:

class Vote {
    static belongsTo = [shareHolder: ShareHolder, candidate: Candidate]
 
    Double voteShares
 
    static constraints = {
        voteShares(min: 0D,
                validator: {
                    val, obj ->
                    val <= obj.shareHolder?.shares
                })
    }
}

As you can see, the obj that gets passed in is the instance that is being validated. The val is the value of the property being validated, in this case the voteShares property. All that has to be done is to compare the value of the obj.shareHolder?.shares too the voteShares property. The obj.shareHolder?. should protect us against a null reference in case the shareHolder isn’t set. Then the validation will just fail on not having the ShareHolder.

Nothing really tricky here, just something interesting I ran into recently.

Posted in Groovy | Tagged , | Leave a comment

Mobile Free (Partial Solution – Calendar Edition)

The holy grail is to have a computer at home, a computer at work and a computer (or a phone) in your pocket. Those things have calendars and contacts and email on them. You might use them at different times, but in the end, you want to know what you need to do tomorrow while you’re sitting on the couch surfing the web on your MacBook Pro. And you want to know if you have plans tonight while your at work figuring out if you have time to start one more thing.

MobileMe seemed like a promising service that would do all of this, allowing you to sync all of your computers with the data on your iPhone. It happened over-the-air and gave all of the systems the same, unified view. And it works. Sort of. As long as you’re just using a Mac and an iPhone. Usually.

Outlook support seems to be incredibly hit and miss. To the point where it’s just not worth the hassle. You can read the forums about all the trouble people are having syncing with Outlook. Some people blame it on having Outlook hooked up to Exchange. Hello? That’s like saying your browser won’t work hooked up to the web? Who uses Outlook willingly without Exchange involved?

Partial Solution – WebDAV

Setup a WebDAV Server

There are plenty of Web Servers out there and plenty of hosting services. Many of them can support WebDAV. I’m using Apache 2.2 as my Web Server so I setup WebDAV there. Your configuration might vary based on what you are using of course.

Apache Configuration

I created a new virtual host for my WebDAV server and configured it as such:

<VirtualHost *:80>
    ServerName dav.zorched.net
 
    DavLockDB /var/www/var/DavLock
    DocumentRoot /var/www/dav
    <Directory />
        AuthType Basic
        AuthName "Zorched.net DAV"
        AuthUserFile /etc/apache2/dav_svn.passwd
        Require valid-user
 
        Dav On
    </Directory>
 
    ErrorLog /var/log/apache2/dav_error.log
 
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
 
    CustomLog /var/log/apache2/dav_access.log combined
    ServerSignature On
</VirtualHost>

Publish your Outlook 2007 Work Calendar to WebDAV

In Outlook. Right click on a Calendar and Choose Publish to Internet -> Publish to WebDAV Server

Publish Outlook Calendar to WebDAV

Publish Outlook Calendar to WebDAV

Enter in a path to an existing directory on the WebDAV server. This copies an ics file out to your WebDAV server and will periodically update it out on the server.

Publish your Apple iCal Calendar to WebDAV

In Apple iCal. Right click on your calendar and choose Publish. In the Publish on drop down, choose a Private Server and enter in the proper details.

Publish your home calendar from Apple iCal

Publish your home calendar from Apple iCal

This will push the calendar out to the server so that you can subscribe to it from Outlook.

Subscribe to your Home Calendar in Outlook 2007

In Outlook. Choose Tools -> Account Settings from the toolbar. Then choose the Internet Calendars tab. Click the New… button.

Subscribe to a WebDAV calendar in Outlook

Subscribe to a WebDAV calendar in Outlook

Enter in the full path to the shared ics file on the WebDAV server.

Subscribe to your Work Calendar in Apple iCal

In Apple iCal. Choose the menu Calendar -> Subscribe and enter in the URL of the work calendar.

Subscribe to a shared Calendar in iCal

Subscribe to a shared Calendar in iCal

Limitations

Now I sync my iPhone with my MacBook pro and all of the info gets onto the iPhone. Any changes on the iPhone to the Home calendar get pushed into iCal and get synced up to the WebDAV server. So the next day when I come into the office they show up in Outlook when it pulls down the changes from the Home calendar.

This is not MobileMe though. There is no over-the-air syncing. Each of the calendars is still only editable from its origin. (You can only edit the Work calendar from Outlook and the Home calendar from iCal.) But it works.

Posted in Mac OS X, WebDAV | Tagged , , , | Leave a comment

Erlang Examples: GUIs and Error Handling

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Robustness in Erlang, and use of a graphics package

Excercise: Create a window containing three buttons: Quit , Spawn , Error.
The Spawn button shall create a child process which displays an identical window.
The Quit button should kill the window and its child windows.
The Error button should cause a runtime error that kills the window (and its children), this window shall then be restarted by its parent.

-module(gui).
-export([init/0]).
 
init() ->
    S = gs:start(),
    Win = gs:create(window, S, [{width, 350}, {height, 100}]),
    gs:create(button, quit, Win, [{label, {text, "Quit"}}, {x, 0}]),
    gs:create(button, spawn, Win, [{label, {text, "Spawn"}}, {x, 100}]),
    gs:create(button, error, Win, [{label, {text, "Error"}}, {x, 200}]),
    gs:config(Win, {map, true}),
    loop().
 
loop() ->
    receive
        {gs, spawn, click, _, _} ->
            Pid = spawn(?MODULE, init, []),
            handle_error(self(), Pid),
            io:format("got here~n",[]),
            loop();
        {gs, quit, click, _, _} ->
            io:format("quitting~n",[]),
            gs:stop();
        {gs, error, click, _, _} ->
            erlang:error(errorclick);
        exit ->
            bye
    end.
 
handle_error(MasterPid, Pid) ->
    spawn(fun() ->
                  process_flag(trap_exit, true),
                  link(Pid),
                  receive 
                      {'EXIT', Pid, {errorclick, _}} ->
                          io:format(" ~p died :~n",[Pid]),
                          MasterPid ! {gs, spawn, click, a, b};
                      _ ->
                          io:format(" really quitting :~n", []),
                          MasterPid ! exit
                  end
          end).

gs

The gs code is all GUI code. It just goes to show that you can use FP to create GUIs even if it’s not quite as intuitive as it might be in an OO language. It creates a windows with a series of buttons on it.

handle_error

This handle_error code shows linking a Process to another error handler process. That spawns a process whose sole purpose is to listen for errors from the main process. If an {‘EXIT’, Pid, {errorclick, _}} error is received the error handler sends a message back asking the MasterPid to spawn a new window.

Posted in Erlang | Tagged | Leave a comment

Capistrano and Ferret DRB

This is a bit of a followup to my previous post on Capistrano with Git and Passenger. I decided to use Ferret via the acts_as_ferret (AAF) plugin. Ferret is a full-text search inspired by Apache’s Lucene but written in Ruby.

Basically Ferret and Lucene keep a full-text index outside of the database that allows it to quickly perform full-text searches and find the identifers of rows in your database. Then you can go get those objects out of the database. It’s pretty slick.

Ferret uses DRb as a means of supporting multiple-concurrent clients and for scaling across multiple machines. You really don’t need to know much about DRb to use AAF, but you do need to run the ferret DRb server in your production environment. Which gets us to…

Automating The Starting and Stopping of ferret_server

A few lines of code in your Capistrano deploy.rb and you are off and running.

before "deploy:start" do 
  run "#{current_path}/script/ferret_server -e production start"
end 
 
after "deploy:stop" do 
  run "#{current_path}/script/ferret_server -e production stop"
end
 
after 'deploy:restart' do
  run "cd #{current_path} && ./script/ferret_server -e production stop"
  run "cd #{current_path} && ./script/ferret_server -e production start"
end

Except it doesn’t work. I ended up with some errors like:
could not execute command
no such file to load — /usr/bin/../config/environment

It also ends up that it’s not Capistrano’s fault.

Acts As Ferret server_manager.rb

In the file vendor/plugins/acts_as_ferret/lib/server_manager.rb there is a line that sets up where to look for its environment information. For some reason this is the default:

  # require(File.join(File.dirname(__FILE__), '../../../../config/environment'))
  require(File.join(File.dirname(ENV['_']), '../config/environment'))

If you notice, there is a line commented out. It just so happens that uncommenting that line and commenting out the other fixed the issue for me. It ends up that ENV['_'] points to the base path of the executable and thats /usr/bin/env. And that doesn’t work. I’m not sure why that’s the default behavior.

Anyway, it’s easily fixed:

  require(File.join(File.dirname(__FILE__), '../../../../config/environment'))
  # require(File.join(File.dirname(ENV['_']), '../config/environment'))

With that fix in place, the Capistrano deployment will restart the Ferret DRb server when you deploy your application.

Update
According to John in the comments below you can fix the AAF problem without changing the code as well. Just add default_run_options[:shell] = false to your Capistrano script and that will take care of it.

Posted in Automation, Ruby | Tagged , , | 3 Comments

Capistrano Deploy with Git and Passenger

One of the great things about Rails and its community is that they are very lazy. Lazy in the good way of not wanting to do boring, repetitive, error prone things manually. They metaprogram and they automate. A great example of this is Capistrano. Capistrano allows you to deploy Rails applications with ease. The normal scenario is baked into Capistrano as a deployment convention and then you can customize it if you need to.

My Story

I’ve recently redeployed a couple of Ruby on Rails sites using Passenger (mod_rails). Passenger is an Apache module that really simplifies the deployment of small-scale Rails applications. Once Passenger is installed and your Rails application is set up as a virtual directory, it just works. Passenger auto-detects the fact that the directory is a Rails application and runs it for you. No need for a mongrel cluster or manually configuring load balancing.

I’m also using Git as my version control system on small, personal projects because it’s easy to use and I can work on multiple laptops and commit locally and worry about pushing to a central location when I have a network connection.

Seeing those things, I wanted to make them all work with Capistrano so that I could continue being lazy. To do this, I’m using Capistrano v2.4. It has Git support built in that works (some previous versions had support for Git, but seemed to have a lot of trouble).

Git Setup

By convention, Capistrano uses Subversion. So, I need to change my configuration to use git. The set :scm, :git does this. The repository information sets up where my git repository lives. In this case, I’m just using a bare git repository accessing it over SSH. You can also access your repository using the git and http protocols if you have that setup. The branch just says to deploy off of the master branch.

That’s pretty much it – nice and easy.

set :scm, :git
set :repository, "geoff@zorched.net:myapp.git"
set :branch, "master"
set :deploy_via, :remote_cache

Passenger (mod_rails) Setup

The only thing that comes into play with Passenger is restarting the Rails application after a deployment is done. Passenger has an easy way to do this which is just to create a file called restart.txt in the Rails tmp directory. When it sees that, the Rails application process will be recycled automatically.

Doing this requires just a bit of Capistrano customization. We need to override the deploy:restart task and have it run a small shell script for us. In this case we are running run “touch #{current_path}/tmp/restart.txt” to accomplish this task.

namespace :deploy do
  desc "Restarting mod_rails with restart.txt"
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{current_path}/tmp/restart.txt"
  end

We can also override the start and stop tasks because those don’t really do anything in the mod_rails scenario like they would with mongrel or other deployments.

  [:start, :stop].each do |t|
    desc "#{t} task is a no-op with mod_rails"
    task t, :roles => :app do ; end
  end
end

The Whole Thing

Putting everything together in my deploy.rb looks like the following:

set :application, "enotify"
 
# If you aren't deploying to /u/apps/#{application} on the target
# servers (which is the default), you can specify the actual location
# via the :deploy_to variable:
set :deploy_to, "/var/www/myapp"
 
# If you aren't using Subversion to manage your source code, specify
# your SCM below:
set :scm, :git
set :repository, "geoff@zorched.net:myapp.git"
set :branch, "master"
set :deploy_via, :remote_cache
 
set :user, 'geoff'
set :ssh_options, { :forward_agent => true }
 
role :app, "zorched.net"
role :web, "zorched.net"
role :db,  "zorched.net", :primary => true
 
namespace :deploy do
  desc "Restarting mod_rails with restart.txt"
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{current_path}/tmp/restart.txt"
  end
 
  [:start, :stop].each do |t|
    desc "#{t} task is a no-op with mod_rails"
    task t, :roles => :app do ; end
  end
end
Posted in Ruby | Tagged , , , | 13 Comments

Package Grails DBMigrations in your WAR File

The Grails DBMigrate Plugin is a handy way to give you control over the generation of your database if you don’t want Grails to auto-munge your schema. It works fine in development, but when you create a WAR for deployment on another machine the Migrations are not packaged in the WAR so the database can’t be created or updated.

Packaging DBMigrate Scripts for Deployment

Here’s the quick solution to package your DBMigrations in your WAR file.

Just add this to your Config.groovy file and when you generate the WAR the migrations will be included and found by the Plugin.

grails.war.resources = {stagingDir ->
    copy(todir: "${stagingDir}/WEB-INF/classes/grails-app/migrations") {
        fileset(dir:"grails-app/migrations")
    }
}

Aside

The only problem with DBMigrate is that it doesn’t handle creating or updating Stored Procedures and Functions which means if you want to use those – for Reporting purposes lets say – you’re out of luck currently.

Posted in Groovy | Tagged , | 2 Comments

Erlang Examples: Talk with Erlang

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Implementing Talk with Distributed Erlang

Make a simple Talk program that makes it possible to chat with friends at other nodes/hosts.
Hints: Your program should consist of two registered processes one for reading from the terminal and the other one for recieving messages from the other node then writing them to the terminal.

-module(talk2).
-compile(export_all).
start() ->
    OtherNode = clean(io:get_line('What node? ')),
    FullNode = string:concat(OtherNode, "@localhost"),
    io:format("talking to: ~s~n", [FullNode]),
    register(receiver, spawn(?MODULE, receiver, [])),
    register(sender, spawn(?MODULE, sender, [list_to_atom(FullNode)])),
    get_input().
get_input() ->
    Message = clean(io:get_line('Talk: ')),
    case string:equal("exit!", Message) of
        true ->
            receiver ! done,
            sender ! done;
        false ->
            talk(Message),
            get_input()
    end.
talk(Message) ->
    sender ! {send, Message}.
sender(OtherNode) ->
    receive
        {send, Message} ->
            rpc:call(OtherNode, talk2, send_message, [Message]),
            sender(OtherNode);
        done ->
            void
    end.
send_message(Message) ->
    receiver ! {message, Message}.
receiver() ->
    receive
        {message, Message} ->
            io:format("~s~n", [Message]),
            receiver();
        done ->
            void
    end.
clean(Data) ->
    string:strip(Data, both, $\n).

Explanation

This is functionally similar to Erlang Talk with Sockets. The difference is that it is doing Erlang-to-Erlang only communication taking advantage of Erlang’s distributed functionality. The Socket example could have been made to interact with any programming language that can do socket programming.

start() ->
This starts the application by asking the user for the name of the other Erlang node to talk to. Erlang nodes are started by running them with a node name erl -name foo. That along with host information are used to talk to a remote node.

So, first using io:get_line(‘What node? ‘) we ask the user then name of the other node. Then we spawn 2 processes. One to receive messages and one to send them. The interesting part here is the use of the register function. It takes an atom and a process id. The register function basically binds a pid to an atom and creates a globally accessible pid. It just simplifies the code a bit so you don’t have to pass those pids to all of the other functions.

get_input() ->
This is the main user input loop. It asks the user for a message and then sends that message to the sender process. io:get_line(‘Talk: ‘) waits for user input before it returns, so only after a user types something and hits return will this function continue. If the case string:equal(“exit!”, Message) do evaluates to true, then the sender and receiver processes are told to exit and the program ends naturally. Otherwise the message is sent.

talk(Message) ->
This function sends the message to the sender process.

sender(OtherNode) ->
This is the function that is running as the sender process. It is initialized with the remote OtherNode information. It receives messages and forwards them to the OtherNode. The rpc:call(OtherNode, talk2, send_message, [Message]), call invokes the send_message function running on the remote node.

send_message(Message) ->
This is really an RPC helper method that passes messages it get to the process running the receive function.

receiver() ->
The receiver is the function that is being run as the receiver process. It listens for messages and when it gets one it prints it out to the user.

Thoughts

The other interesting way to solve this would be to actually spawn processes remotely on the other node. The code can then have a reference to a pid running on the remote node and can pass messages to it directly without using the RPC approach. This would allow one side of the conversation to initiate it without the other knowing about it.


register(remote_receiver, spawn(OtherNode, talk2, receiver, [])),
remote_receiver ! "Hello".

An exercise I’ll leave up to you!

Posted in Erlang | Tagged | 2 Comments

Erlang Examples: Talk with Sockets

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Erlang using UNIX sockets

Do you want to talk with a friend on another machine? Shouldn’t it be nice to have a shell connected to your friend and transfer messages in between?
This can be implemented using the client/server concept with a process on each side listening to a socket for messages.

-module(talk).
-compile(export_all).
start(LocalPort, RemotePort) ->
    ServerPid = spawn(?MODULE, start_server, [LocalPort]),
    cli(RemotePort, ServerPid).
cli(RemotePort, ServerPid) ->
    Data = clean(io:get_line('Message: ')),
    case should_stop(Data) of
        true ->
            ServerPid ! done;
        false ->
            spawn(?MODULE, send, [RemotePort, Data]),
            cli(RemotePort, ServerPid)
    end.
clean(Data) ->
    string:strip(Data, both, $\n).
should_stop(Str) ->
    0 =:= string:len(Str).
start_server(Port) ->
    case gen_tcp:listen(Port, [binary, {packet, 4},
                               {reuseaddr, true},
                               {active, true}]) of
        {ok, Listen} ->
            server(Listen);
        {error, Reason} ->
            {error, Reason}
    end.
server(Listen) ->
    case gen_tcp:accept(Listen) of
        {ok, Socket} ->
            server_loop(Socket),
            server(Listen);
        _ ->
            ok
    end.
server_loop(Socket) ->
    receive
        done ->
            gen_tcp:close(Socket),
            io:format("Server socket closed~n");
        {tcp, Socket, Bin} ->
            Str = clean(binary_to_term(Bin)),
            io:format("~p~n", [Str]),
            case should_stop(Str) of
                true ->
                    void;
                false ->
                    server_loop(Socket)
            end;
        {tcp_closed, _Socket} ->
            ok
    end.
send(Port, Data) ->
    case gen_tcp:connect("localhost", Port, [binary, {packet, 4}]) of
        {ok, Socket} ->
            gen_tcp:send(Socket, term_to_binary(Data)),
            gen_tcp:close(Socket);
        {error, Reason} ->
            {error, Reason}
    end.

Explanation

start(LocalPort, RemotePort) ->
The entry point to the talk program. This spawns a new start_server process that will handle opening a socket and listening for messages from a remote client. It then runs the command line interface and waits for data from the user to send to the remote port.

cli(RemotePort, ServerPid) ->
This is the loop that will get the data from the user and send it to the remote port.

clean(Data)
This is a simple function that removes the newlines from the end of the data sent to the client.

should_stop(Str)
This is a simple function that determines whether the client and server should shut down. The rule is that if it’s an empty string then the processes should stop.

start_server(Port) ->
This function gets run in a process and opens a Listening socket. It then hands off to server(Listen) -> to handle dealing with new incoming socket connections.

server(Listen) ->
The server gets a new Socket when an incoming connection connects to the Listening port. It then goes into a receive state and waits for an incoming connection to send it data. The receive state is handled in the server_loop.

send(Port, Data) ->
This is the client side of the application. It connects to a remote port and sends the data to that port.

case … of
In a number of these functions you see a common idiom:

case fun() of
    SomeMatch ->
        Do something;
    AnotherMatch ->
        Do something else
end

With socket connections and many others it is common to return a tuple like {ok, Val} when the function call is successful and will return {error, Reason} or a similar tuple when there is an error in the function. The case statement is just an easy way to handle these differences.

Posted in Erlang | Tagged | 3 Comments

Erlang Example: Star Messages

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Interaction between processes, Concurrency

3) Write a function which starts N processes in a star, and sends a message to each of them M times. After the messages have been sent the processes should terminate gracefully.

-module(star).
-export([start/2, loop/0, sendMessage/2]).
start(0, _) ->
    io:format("done~n", []);
start(N, M) ->
    timer:sleep(random:uniform(10) * 100),
    LoopPid = spawn(?MODULE, loop, []),
    spawn(?MODULE, sendMessage, [M, LoopPid]),
    start(N - 1, M).
sendMessage(0, Pid) ->
    Pid ! done;
sendMessage(M, Pid) ->
    timer:sleep(random:uniform(5) * 100),
    Pid ! M,
    sendMessage(M - 1, Pid).
loop() ->
    receive
        done ->
            io:format("* Process: ~10w, Message#: terminate!~n", [self()]);
        R ->
            io:format(": Process: ~10w, Message#: ~w ..~n", [self(), R]),
            loop()
    end.

Explanation

start(N, M)
The entry point to the code defines the Number of processes to start and the number of Messages to pass. timer:sleep(random:uniform(10) * 100), is just to demonstrate that things are actually happening concurrently. Without this the program usually runs to fast and everything is sequential. LoopPid = spawn(?MODULE, loop, []), creates a new process running the loop function. That process is set up to receive messages and print some information out. spawn(?MODULE, sendMessage, [M, LoopPid]), is then called to create a new process whose job it is to send each LoopPid (really the nodes in the star) M number of messages. Finally start(N – 1, M). is called tail recursively with one less Node count.

start(0, _)
This function is called or matched when the tail recursion from start(N, M) finally gets down to the value where N is zero. In that case we no longer want to spawn processes so we just write “done” and exit the function.

sendMessage(M, Pid)
Following a similar pattern to the start function this counts down M to zero and sends M as a message to the given Pid. The tail recursion handles decrementing to the count of M until the pattern (0, Pid) is matched at which point sendMessage(0, Pid) is matched and the Pid is sent the ‘done’ message.

loop()
This is the function that is run as the individual processes or the “points of the star”. Its job is to receive messages passed to it. When done -> is matched by a message, the process will print out some information and then end gracefully. R -> represents a message being passed with a single value that is anything other than the atom ‘done’. When it is matched the value is printed and the process waits for another message by calling back to itself with loop()

Thoughts

One of the interesting things to me is the tail recursion of Erlang and other Functional Programming Languages. This accomplished the same thing as a looping construct without using for or while or any of those usual imperative methods.

Posted in Erlang | Tagged | Leave a comment