Skip to main content

Actors in Java: Coding The Surveillance And Security Application Part 3

Posted by jcmansigian on December 9, 2013 at 12:12 PM PST

This post presents the completion of the light weight surveillance and security framework that I wrote for the express purpose of teaching actor programming techniques available with Java and the Akka actor framework. Complete running code is available for study and/or as a base for your own project. While the project is nominally about software to surveill and secure complex premises such as office buildings and shopping malls it really is a model of an actor based distributed system that can be remotely deployed and features the ability to monitor itself and engage in self-repair through managed automatic restart of failed units.

What You Will Need

To work with the code that comes with this post you will need to have the following installed on all of the machines you intend to use.


Because we will be creating a distributed system with remote deployment be aware that you must have all of the Akka provided jar files visible to each JVM on all of the machines that you will be using. Set classpaths accordingly in your IDEs or scripts. The scripts that come with the source for SurveilSecure are a guide to what you will need in your own custom setup

.

Getting Started

If you are not already familiar with this code the best thing to do is to see Actors in Java: Coding the Surveillance and Security Application Part 2. A link to this can be found at the top of this page. Reading through that post and examining the attached code will set the context for following this post.

What Has Changed

The thing that is different from the code that accompanied the last post to this one is the completion of the mechanism that allows the system to be self aware and self healing. To accomplish these goals I make use of the abilities of the Akka framework to implement self awareness and self healing. Akka has two ways of extending these virtues; supervision and life cycle monitoring. Supervision involves a parent actor supervising child actors it has created. What we have in the example code is life cycle monitoring. In life cycle monitoring or death watch as it is also called there does not necessarily have to be a parent child relationship. Any actor can monitor any other actor. What happens is that when a watched actor ( actor being monitored by another actor ) terminates for any reason a termination message is sent to the monitoring actor. The monitoring actor can determine from the message which actor sent it. At the point the monitoring actor can decide if it is appropriate under the conditions of failure to restart the crashed actor. We can turn to some actual code to see how this happens.

First we will see how to set up life cycle monitoring.

// Create the surveillance remote actor system.
surveilSystem = ActorSystem.create(
     "Surveil", ConfigFactory.load().getConfig("Surveil"));
// Create the actor that manages surveillance.
surveilRef = surveilSystem.actorOf(
      Props.create( Surveil.class ), "Surveil" );
// Set up life cycle monitoring on the surveillance manager.
this.getContext().watch( surveilRef );

The above code creates a remote actor system and creates within that actor system the actor that will be the manager of a major functional unit, namely surveilance. Monitoring of the actor referenced by surveilRef by the Control actor is accomplished by only line of code:

this.getContext().watch( surveilRef ); 

Once monitoring has been set up the monitoring actor, Control, waits in its receive loop for a Terminated message. Of course in the mean time it is doing other things precipitated by other message types. But if a
Terminated message comes through it will be detected and acted upon by the code below.

// Test for termination of watched actor.
  if ( messageRecv instanceof Terminated )
  {
     System.out.println( "\nControl: Detected death of watched actor.");
     final Terminated t = (Terminated) messageRecv;
     ActorRef deadActorRef = t.getActor();

      if ( deadActorRef.equals( surveilRef ))
      {
           // We will try to restart the surveillance manager.
   System.out.println("\nControl: Surveil terminated unexpectedly. ");
   // Delay to get around transient external problem ( net, database ).
   Common.pause( Constants.RESTART_DELAY );
    // Restart the actor with clear initial state.
    if ( surveilRestarts < Constants.RESTART_LIMIT )
    {
        surveilRef = Common.restart(
                surveilSystem, Surveil.class, "Surveil", ++surveilRestarts );
    }
    else
    {
System.out.println("\nControl: Surveil exceeded restart limit. No restart.");
    }
   // Set up life cycle monitoring on the surveillance manager.
   this.getContext().watch( surveilRef );
      }//end Surveil restart processing

Let's go through the code above. First there is a test to determine if the message object received is an instance of the Terminated class. Terminated objects are what is always sent to the monitoring actor when a watched actor terminates. The next thing is to cast the object message to type Terminated and get the actor reference from it.

final Terminated t = (Terminated) messageRecv;
ActorRef deadActorRef = t.getActor();

Once we have an actor reference then we have the identity of the terminated actor which is crucial to being able to restart the failed actor.

The rest of the code tests how many times we have tried to restart this actor and calls a static method Common.restart() which is really just a wrapper of creating an actor from an Actor System object and configuration information. You can view that in Common.java.

This is all there is to a minimum approach to detecting remote failure and restarting the failed actor.

Exercising The Code

You can view how damage control works by doing the following. Execute the "start" script to bring up all of the actors. When you see a message "Ready..." then, from another terminal window, execute "stopSurveil". This will terminate the Surveil actor causing the Akka framework to send a Terminated message to Control. Control will restart the Surveil actor. You can try this many times until you reach the limit and Control refuses to restart the actor again. This will also work for Secure and Alarm with their respective start scripts. When you are done executing "stopControl" will bring the application to a halt.

What's Next

I will be away on vacation for the holidays and will be heavily engaged in launching a startup business in the early part of the new year. After things settle down a bit in 2014 I will be back with innovative actor software.

AttachmentSize
SurveilSecureFinal.zip23.17 KB

Comments

Very good it is the first real example using Akka with Java ...

Very good it is the first real example using Akka with Java I found around. I am quite new in Akka; I see it very powerful but for me it is quite difficult to assimilate the logic behind. For example how do you integrate a existing standard java application with akka? Imagine the system has to start a "calculator" and then check to see if it crashes or if it is closed.

Hello Takaya, The exercise makes use of untyped actors. ...

Hello Takaya,

The exercise makes use of untyped actors. There are also typed actors. These are useful at the periphery of your system to integrate with non-actor code. Even more convenient is the use of the Akka Camel module that allows untyped actors to communicate with exogenous non-actor agents. See:
http://doc.akka.io/docs/akka/snapshot/scala/camel.html