JMU
Mobile Agents
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Definitions
RMI vs. Mobile Agents
The Process

A UML Sequence Diagram

images/mobile_agent_sequence.gif
Minimal Requirements for Mobile Agents
A Simple Implementation - States
A Simple Implementation - States (cont.)
images/mobile_agent_states.gif
A Sandbox for Mobile Agents

Using a Variant of the Strategy Pattern or Command Pattern

images/mobile_agent_sandbox.gif
A Simple Implementation

The Sandbox

javaexamples/agents/Sandbox.java
/**
 * A Sandbox that an Agent can "play" in.
 *
 * Each Sandbox runs in its own thread of execution.
 * It runs its Agent in that thread.
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class Sandbox implements Runnable
{
    private Agent         agent;
    private Thread        controlThread;

    /**
     * Explicit Value Constructor
     *
     * @param agent  The Agent to execute
     */
    public Sandbox(Agent agent)
    {
       this.agent = agent;

       controlThread = new Thread(this);
    }

    /**
     * The code to execute in this Sandbox object's
     * thread of execution
     */
    public void run()
    {
       agent.run();
    }

    /**
     * Start this Sandbox
     */
    public void start()
    {
       controlThread.start();
    }
    
}
        
A Simple Implementation (cont.)

The Sandbox Server

javaexamples/agents/SandboxServer.java
import java.io.*;
import java.net.*;


/**
 * An server that creates Sandbox objects for Agent
 * objects
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison Univeristy
 */
public class SandboxServer
{
    public static final int    PORT = 9200;
    public static final String EXT  = ".class";


    /**
     * The entry point of the application
     *
     * @param args   The command-line arguments
     */
    public static void main(String[] args)
    {
       Agent                agent;
       byte[]               byteCodes;
       Class                agentClass;
       FileOutputStream     out;
       ObjectInputStream    in;
       Sandbox              sandbox;
       ServerSocket         ss;
       Socket               s;
       String               agentName;


       try 
       {
          ss = new ServerSocket(PORT);

          while (true) 
          {
             s = ss.accept();
             in = new ObjectInputStream(s.getInputStream());

             // Read the class name
             agentName = (String)in.readObject();

             // Read the byte codes
             byteCodes = (byte[])in.readObject();

             // Save the class on the local file system
             // for tracking purposes
             out = new FileOutputStream(agentName+".class");
             out.write(byteCodes);

             // Read the Agent
             agent = (Agent)in.readObject();

             // Run the Agent in its own Sandbox
             sandbox = new Sandbox(agent);
             sandbox.start();
             

             in.close();
             s.close();
          }
       } 
       catch (Exception ex) 
       {
          ex.printStackTrace();
       }
        
    }
    
}
        
A Simple Implementation (cont.)

The Agent

javaexamples/agents/Agent.java
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * A simple mobile agent
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public abstract class Agent implements Runnable,
                                       Serializable
{
    private byte[]             byteCodes;
    private LinkedList<String> hosts;
    private String             home;


    public static final int    PORT = 9200;
    public static final String EXT  = ".class";



    /**
     * Explicit Value Constructor
     *
     * @param home   The "home" host
     */
    public Agent(String home)
    {
       FileInputStream        in;


       byteCodes = null;

       try 
       {
          in = new FileInputStream(getName()+EXT);
          byteCodes = new byte[in.available()];
          in.read(byteCodes);
       }
       catch (IOException ioe) 
       {
          byteCodes = null;
       }

       this.home = home;
    }



    /**
     * Add a host to the top of the stack
     *
     * @param host    The host
     */
    public void addHost(String host)
    {
       hosts.addFirst(host);
    }


    /**
     * The code that should be executed before this
     * Agent leaves home
     */
    public abstract void beforeDeparture();


    /**
     * Get the Java byte codes for this Agent
     *
     * @return    The byte codes
     */
    public byte[] getByteCodes()
    {
       return byteCodes;
    }



    /**
     * Get the name of the class for this Agent
     *
     * @return   The name
     */
    public String getName()
    {
       return getClass().getName();
    }



    /**
     * Move this Agent to a Sandbox
     *
     * @param host   The host to go to
     */
    public void goTo(String host)
    {
       ObjectOutputStream    out;
       Socket                s;


       try 
       {
          s = new Socket(host, PORT);
          out = new ObjectOutputStream(s.getOutputStream());

          out.writeObject(getName());
          out.writeObject(getByteCodes());
          out.writeObject(this);
       }
       catch (IOException ioe) 
       {
          host = hosts.getFirst();
          hosts.removeFirst();
          if (host != null) goTo(host);
       }
    }





    /**
     * The code that should be executed when this
     * Agent arrives at a remote Sandbox
     */
    public abstract void onArrival();


    /**
     * The code that should be executed when this
     * Agent returns home
     */
    public abstract void onReturn();








    /**
     * The entry point for the controlling thread
     * of execution
     */
    public void run()
    {
       String         host;


       if (hosts == null) 
       {
          hosts = new LinkedList<String>();
          hosts.addLast(home);
          beforeDeparture();
       }
       else if (hosts.size() == 0) 
       {
          onReturn();
       }
       else 
       {
          onArrival();

          host = hosts.getFirst();
          hosts.removeFirst();
          goTo(host);
       }


       // Drop out of the run method which
       // will terminate the thread on the old
       // Sandbox
    }
    
}
        
A Simple Implementation (cont.)

A Particular Agent - Kilroy

javaexamples/agents/Kilroy.java
import java.awt.*;
import java.io.*;

/**
 * A simple Agent that makes you aware
 * of its arrival
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class Kilroy extends Agent
{

    /**
     * Explicit Value Constructor
     *
     * @param home   The "home" host
     */
    public Kilroy(String home)
    {
       super(home);
    }



    /**
     * The code that should be executed before this
     * Agent leaves home
     */
    public void beforeDeparture()
    {
       goTo("localhost");
    }



    /**
     * The code that should be executed when this
     * Agent arrives at a remote Sandbox
     */
    public void onArrival()
    {
       Frame   f;


       f = new Frame("Kilroy");
       f.setLayout(new BorderLayout());
       f.add(new Label("Kilroy Was Here!", Label.CENTER));
       f.setSize(400,50);
       f.show();
       f.toFront();

       try { Thread.sleep(5000); } catch (InterruptedException ie){};

       f.dispose();
    }



    /**
     * The code that should be executed when this
     * Agent returns home
     */
    public void onReturn()
    {

    }
}
        
Advantages of Mobile Agents
Extensions
Extensions (cont.)