5. Movilidad


5.1 Soporte de la movilidad en JADE

5.2 API JADE para movilidad

5.3 Ontología Jade para movilidad

5.4 Accediendo al AMS para movilidad

5.5 Ejercicios


Nota: Para los ejemplos y el ejercicio crear una carpeta en C:\jade\src\examples\ denominada Movilidad.

5.1 Soporte de la movilidad en JADE


La movilidad de un agente es la habilidad para que este migre o haga una copia de sí mismo (clon) a través de uno o múltiples nodos de una red. El soporte de movilidad en JADE consiste en un conjunto de clases, métodos y una ontología específica de movilidad (MobilityOntology). Las clases y métodos permiten a un agente ejecutar las acciones requeridas por sí mismo o por el AMS (Agent Management System).
Esta versión de JADE soporta solo movilidad dentro de la misma plataforma. Esto quiere decir que un agente móvil se puede mover a través de contenedores pero está limitado a una sola plataforma. Existe un proyecto de la Universidad autónoma de Barcelona que implementa el servicio de movilidad inter-plataforma de movilidad llamado IPMS (Inter-Platform Mobility Service), el cual puede permitir migrar de una plataforma a otra distinta.
Cada instancia de ejecución en JADE se llama contenedor. El conjunto de todos los contenedores se llama plataforma y proporciona una capa homogénea que esconde los agentes, la aplicación desarrollada, la complejidad y los contenedores. Por lo tanto, tenemos que:
  • Se involucran varios hosts.
  • Cada host tiene su contenedor.
  • La migración puede suceder a petición del propio agente.

VENTAJAS:
  • Proceso independiente y asíncrono: Cuando un agente migra no es necesario que siga en contacto con su propietario para realizar su cometido. Un agente puede migrar y realizar una tarea complicada y cada cierto tiempo informará sobre los resultados.
  • Tolerancia a fallos: Cuando se detectan problemas, los agentes móviles pueden migrar a otra plataforma y probar suerte allí sin que se detenga la ejecución.
  • Apropiados para conjuntos grandes de datos: Los agentes se desplazan hacia donde se encuentran los datos y no al revés, ahorrando en transferencia de información y ganando en procesamiento.


INCONVENIENTES:
  • Escalabilidad y rendimiento: Aunque reducen el tráfico en red, generan un incremento de carga de procesamiento. Esto es porque son generalmente programados en lenguajes interpretados.
  • Seguridad: El uso de agentes móviles puede traer problemas de seguridad. Cualquier código móvil debe ser revisado cautelosamente.
  • Portabilidad y Estandarización: Los agentes móviles no pueden inter-operar sino siguen unos estándares de comunicación.


MOVILIDAD INTER-PLATAFORMA (IPMS)

El modelo de Movilidad Inter-Plataforma (IPMS) es un complemento de Jade que se ha creado para permitir la movilidad de agentes entre plataformas. La idea es utilizar mensajes FIPA-ACL como medio de transporte. Estos mensajes son enviados entre los AMS de las plataformas finales. Se especifican dos acciones en la ontología, move y power-up. La primera representa el movimiento del código del agente, y la segunda la activación del agente una vez completada la migración inter-plataforma.
Adicionalmente, algunos conceptos de la ontología son mobile-agent-description y mobile-agent-profile que contienen toda la información del agente. Estos conceptos aseguran la compatibilidad entre plataformas. El proceso es el siguiente:
  • Se envía un Request a la plataforma destino esperando respuesta.
  • Si obtenemos un Inform el agente puede serializarse y enviarse dentro de un mensaje a la plataforma destino.
  • Si ocurren algún problema durante este traspaso de información se desharán todos los cambios.
La ventaja de utilizar mensajes ACL es que no es necesario abrir otro canal de comunicación entre plataformas. La desventaja es que el rendimiento no es particularmente alto debido al proceso de codificación y decodificación del propio mensaje ACL.
La siguiente figura muestra el ejemplo más sencillo de movilidad en Jade. Desde la interfaz gráfica se puede hacer que un agente se mueva de un contenedor a otro dentro de la misma plataforma. Solamente hay que seguir los pasos indicados:
  1. Botón derecho sobre el agente a mover. Opción "Migrate Agent".
  2. Ventana "Insert Parameters". En el cuadro de texto "Container" introducimos el nombre del contenedor al que queremos mover nuestro agente.
  3. Nuestro agente aparece en el contenedor indicado.




A la hora de ejecutar un agente en una plataforma situada en un host remoto, se debe hacer uso del parámetro host:
java jade.Boot -host hostRemoto -container agente1:Agente
donde "hostRemoto" hace referencia a la IP o el nombre del host remoto.

JADE soporta movilidad de código y estado de ejecución: un agente puede dejar de ejecutarse sobre una máquina, migrando sobre diferentes nodos remotos (sin la necesidad de tener el código del agente instalado en ese nodo), y reiniciar su ejecución en el punto en que fue interrumpido (realmente, JADE implementa una forma de movilidad no tan débil, porque la pila y el registro del programa no pueden ser salvados en Java). Esta funcionalidad permite, por ejemplo, distribuir la carga computacional al tiempo de ejecutar los movimientos del agente, a las maquinas menos cargadas sin algún impacto en la aplicación.

La clase Agent de JADE contiene los métodos para llevar a cabo el proceso de movilidad y clonación:
  • doMove()
  • beforeMove()
  • afterMove()
  • doClone()
  • beforeClone()
  • afterClone()

Sin embargo estos métodos requieren de ciertos parámetros (objetos de tipo Location) porque los agentes necesitan conocer su localización para saber cuándo y a dónde desplazarse. Para poder utilizar los objetos de tipo Location debemos incluir el siguiente import:
import jade.core.*;

5.2 API JADE para movilidad


Para mover y clonar un agente la clase Agent dispone de dos métodos, doMove(Location destino) y doClone(Location destino,string nombre).

  • doMove(Location destino): este método recibe como parámetro un objeto de tipo jade.core.Location, que representa el destino requerido donde debe migrar el agente. jade.core.Location es una interfaz abstracta, usada porque las aplicaciones de agentes no pueden crear sus propias localizaciones. Para obtener el objeto Location es necesario hacer una petición al AMS, la cual puede ser de dos tipos, uno es WhereIsAgentAction, que es una clase que contiene un método setAgentIdentifier(AID), que recibe como parámetro el identificador del agente del que se quiere obtener el objeto Location, que indica la localización del container de dicho agente. Esto se puede obtener mediante el método getAgentIdentifier(). Sin embargo, si se utiliza QueryPlatformLocationsAction, devolverá los objetos Location de los containers de todos los agentes que estén disponibles, con lo cual, no necesitará recibir ningún parámetro.

  • doClone(Location destino,string nombre): este método recibe dos parámetros, uno es el destino al que debe migrar el nuevo clon del agente, y el otro un string, que será el nombre que se le dará a dicho clon, distinto del original.

El hecho de mover un agente implica enviar su código y estado a través de la red. Algunos de los recursos usados por el agente móvil se moverán con el, mientras que otros serán desconectados antes de salir, y conectados de nuevo, una vez que lleguen al destino. Para gestionar estos recursos, Java proporciona una serie de métodos:

  • beforeClone() y afterClone() permiten al agente realizar tareas específicas antes y después de clonarse.Esto se utilizaría, por ejemplo, en el caso de agentes que son plataformas o contenedores dependientes como la ontología y el lenguaje. Por esta razón, después de que el agente se mueva, se debe registrar otra vez el lenguaje y la ontología.
  • beforeMove(): se invoca en la localización de partida antes de enviar el agente a través de la red (con el scheduler de comportamientos ya parado)
  • afterMove(): se invoca en la localización de destino tan pronto como el agente llega y se identifica en el lugar (el scheduler aún no reiniciado)

Ejemplo: Crear fichero AgenteMovil.java en la carpeta Movilidad.
package examples.Movilidad;
import java.util.*;
import java.io.*;
 
import jade.lang.acl.*;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.core.behaviours.*;
import jade.domain.*;
import jade.core.Runtime;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.core.*;
import jade.domain.JADEAgentManagement.*;
import jade.domain.mobility.*;
 
public class AgenteMovil extends Agent {
  private ArrayList containers = new ArrayList();
  private Location origen = null;
  private Location destino= null;
  private String mensaje = "";
  private boolean movido = false;
 
  //Metodo para actualizar la lista de containers disponibles
  protected void actualizarContainers(){
    origen = here();
    containers.clear();
    ACLMessage request= new ACLMessage(ACLMessage.REQUEST);
    request.setLanguage(new SLCodec().getName());
    // Establecemos que MobilityOntology sea la ontologia de este mensaje.
    request.setOntology(MobilityOntology.getInstance().getName());
    // Le solicitamos al AMS una lista de los containers disponibles
    Action action= new Action(getAMS(), new QueryPlatformLocationsAction());
    try {
      getContentManager().fillContent(request, action);
      request.addReceiver(action.getActor());
      send(request);
 
      // Filtramos los mensajes INFORM que nos llegan desde el AMS
      MessageTemplate mt= MessageTemplate.and(MessageTemplate.MatchSender(getAMS()), MessageTemplate.MatchPerformative(ACLMessage.INFORM));
 
      ACLMessage resp= blockingReceive(mt);
      ContentElement ce= getContentManager().extractContent(resp);
      Result result=(Result) ce;
      jade.util.leap.Iterator it= result.getItems().iterator();
      // Almacena en un ArrayList "Locations" de los "Containers" a los que puede moverse el agente movil.
      while(it.hasNext()) {
    Location loc=(Location) it.next();
    containers.add(loc);
      }
    }catch(Exception ex) {
      ex.printStackTrace();
    }
  }
 
  //Metodo para visualizar los containers disponibles en la plataforma
  protected void verContainers(){
    //ACTUALIZAR
    actualizarContainers();
    //VISUALIZAR
    System.out.println("******Containers disponibles: *******");
    for(int i=0; i<containers.size(); i++){
      System.out.println("["+ i + "] " + ((Location)containers.get(i)).getName());
    }
  }
 
  protected void setup(){
    // Registramos el lenguaje y la ontologia para la movilidad en el manejador del agente
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
 
    actualizarContainers();
    addBehaviour(new MoverAgenteBehaviour(this));
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil antes de desplazarse.
  protected void beforeMove(){
    System.out.println("El agente se marcha");
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil despues de desplazarse.
  protected void afterMove() {
    //Hasta el if se ejecuta dos veces (ida y vuelta)
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
    System.out.println("El agente ha llegado");//llegado desde: "+ origen.getName());
    System.out.println(mensaje);
    if(movido == false){
      movido = true;
      System.out.println("El agente esta leyendo el fichero");
      leerArchivo();
      for(int i=0; i<5; i++){
    System.out.print(".");
    doWait(1000);
      }
      doMove(origen);
    }
  }
 
  class MoverAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public MoverAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() {
      try {
    verContainers();
    System.out.print("Introduce el numero del container al que mover: ");
    BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
    String lectura = lee.readLine();
    int container = Integer.parseInt(lectura);
 
    try{
      destino=(Location)containers.get(container);
      // Metodo al que llama el agente para desplazarse a su nuevo destino.
      doMove(destino);
    }catch(Exception ex){
      System.out.println("Problema al intentar mover el agente");
    }
      }catch(IOException io){
    System.out.println(io);
      }
      parar = true;
    }
 
    public boolean done() {
      return parar;
    }
  }
 
  protected void takeDown(){}
 
  private void leerArchivo(){
    File archivo = null;
    FileReader fr = null;
    try {
      archivo = new File ("fichero.txt");
      if(archivo.exists()){
    String linea;
    fr = new FileReader (archivo);
    BufferedReader br = new BufferedReader(fr);
    while((linea=br.readLine())!=null)
      mensaje = linea;
      }
    }
    catch(IOException e){
      System.out.println(e);
    }
  }
}
 
Ejemplo: Crear fichero AgenteClonar.java en la carpeta Movilidad.
package examples.Movilidad;
import java.util.*;
import java.io.*;
 
import jade.lang.acl.*;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.core.behaviours.*;
import jade.domain.*;
import jade.core.Runtime;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.core.*;
import jade.domain.JADEAgentManagement.*;
import jade.domain.mobility.*;
 
public class AgenteClonar extends Agent {
  private ArrayList containers = new ArrayList();
  private Location origen = null;
  private Location destino= null;
  private String mensaje = "";
 
  //Metodo para actualizar la lista de containers disponibles
  protected void actualizarContainers(){
    containers.clear();
    ACLMessage request= new ACLMessage(ACLMessage.REQUEST);
    request.setLanguage(new SLCodec().getName());
    // Establecemos que MobilityOntology sea la ontologia de este mensaje.
    request.setOntology(MobilityOntology.getInstance().getName());
    // Le solicitamos al AMS una lista de los containers disponibles
    Action action= new Action(getAMS(), new QueryPlatformLocationsAction());
    try {
      getContentManager().fillContent(request, action);
      request.addReceiver(action.getActor());
      send(request);
 
      // Filtramos los mensajes INFORM que nos llegan desde el AMS
      MessageTemplate mt= MessageTemplate.and(MessageTemplate.MatchSender(getAMS()), MessageTemplate.MatchPerformative(ACLMessage.INFORM));
 
      ACLMessage resp= blockingReceive(mt);
      ContentElement ce= getContentManager().extractContent(resp);
      Result result=(Result) ce;
      jade.util.leap.Iterator it= result.getItems().iterator();
      // Almacena en un ArrayList "Locations" de los "Containers" a los que puede moverse el agente movil.
      while(it.hasNext()) {
    Location loc=(Location) it.next();
    containers.add(loc);
      }
    }catch(Exception ex) {
      ex.printStackTrace();
    }
  }
 
  //Metodo para visualizar los containers disponibles en la plataforma
  protected void verContainers(){
    //ACTUALIZAR
    actualizarContainers();
    //VISUALIZAR
    System.out.println("******Containers disponibles: *******");
    for(int i=0; i<containers.size(); i++){
      System.out.println("["+ i + "] " + ((Location)containers.get(i)).getName());
    }
  }
 
  protected void setup(){
    // Registramos el lenguaje y la ontologia para la movilidad en el manejador del agente
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
 
    actualizarContainers();
    addBehaviour(new ClonarAgenteBehaviour(this));
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil antes de desplazarse.
  protected void beforeMove(){
    System.out.println("[MSG] El agente se clona al container: "+ destino.getName());
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil despues de desplazarse.
  protected void afterMove() {
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
    System.out.println("[MSG] El agente ha llegado desde: "+ origen.getName());
    leerArchivo();
    System.out.println(mensaje);
  }
 
  class ClonarAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public ClonarAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() {
      try {
    verContainers();
    System.out.print("Introduce el numero del container en el que clonar: ");
    BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
    String lectura = lee.readLine();
    int container = Integer.parseInt(lectura);
    System.out.print("Introduce el nombre del clon: ");
    String nombre = lee.readLine();
 
    try{
      origen = here();
      destino=(Location)containers.get(container);
 
      // Metodo al que llama el agente para desplazarse a su nuevo destino.
      // Este destino es de tipo "Location".
      doClone(destino, nombre);
 
    }catch(Exception ex){
      System.out.println("Problema al intentar clonar el agente");
    }
      }catch(IOException io){
    System.out.println(io);
      }
    }
 
    public boolean done() {
      return parar;
    }
  }
 
  protected void takeDown(){}
 
  private void leerArchivo(){
    File archivo = null;
    FileReader fr = null;
    try {
      archivo = new File ("arc.txt");
      if(archivo.exists()){
    String linea;
    fr = new FileReader (archivo);
    BufferedReader br = new BufferedReader(fr);
    while((linea=br.readLine())!=null)
      mensaje = linea;
      //System.out.println(linea);
      }
    }
    catch(IOException e){
      System.out.println(e);
    }
  }
}
 

5.3 Ontología Jade para movilidad


Para la movilidad y comunicación entre los agentes necesitaremos una ontología que proporcione una descripción del sistema y acciones que se pueden llevar a cabo. JADE proporciona esta ontología mediante la clase jade.domain.MobilityOntology, que importaremos con la sentencia
import jade.domain.mobility.*;

MobilityOntolgy contiene un total de seis conceptos y cuatro acciones:

  • mobile-agent-description: describe un agente móvil que va a algún sitio. Se representa por la clase interna MobilityOntology.MobileAgentDescription, la cual tiene varios métodos get y set de acuerdo con las reglas para clases de la ontología JADE.

  • mobile-agent-profile: describe el entorno de programación necesario para el agente móvil. Se representa a través de la clase interna MobilityOntology.MobileAgentProfile.

  • mobile-agent-system: describe el tiempo de ejecución usado por el agente móvil. Se representa mediante la clase interna MobilityOntology.MobileAgentSystem.

  • mobile-agent-language: describe el lenguaje de programación usado por el agente móvil. Se representa mediante la clase interna MobilityOntology.MobileAgentLanguage

  • mobile-agent-os: describe el conjunto de operaciones del sistema necesarias para el agente móvil. Se representa mediante la clase interna MobilityOntology.MobileAgentOS

  • location: describe el lugar a donde un agente puede ir. Se representa mediante la clase interna MobilityOntology.Location.

  • move-agent: acción de mover un agente de un lugar a otro. Se representa mediante la clase interna MobilityOntology.MoveAction

  • clone-agent: la acción que representa es la de hacer una copia de un agente, posiblemente ejecutado en otra ubicación. Se representa mediante la clase interna MobilityOntology.CloneAction

  • where-is-agent: la acción de responder con la localización donde un agente se está ejecutando. Se representa mediante la clase interna MobilityOntology.WhereIsAgent.

  • query-platform-locations: la acción de responder con una lista de las ubicaciones de todas las plataformas Se representa mediante la clase interna MobilityOntology.QueryPlatformLocations.


Esta ontología no se ajusta a ninguna especificación FIPA. Según el equipo de desarrollo de JADE, la actualizarán tan pronto como aparezca una especificación FIPA apropiada.

Uso de la ontología de movilidad para decir a un agente que se mueva a un Location en concreto:

5.4 Accediendo al AMS para movilidad


El AMS provee algunas extensiones que dan soporte a la movilidad de agentes y es capaz de realizar las acciones presentes en el jade-mobility-ontology.
Cada acción relacionada con la movilidad se puede solicitar al AMS a través del protocolo FIPA-request, con jade-mobility-ontology como valor del campo ontology y FIPA-SL0 como valor language.

Un comportamiento típico para un agente móvil será preguntar al AMS por localizaciones (bien la lista completa o bien a través de varias acciones where-is-agent), luego el agente será capaz de decidir si, cuando y a donde migrar.

Nota: para poder acceder al AMS es necesario incluir el import:
import jade.domain.JADEAgentManagement.*;

Acciones para la movilidad:
  • move-agent. Esta acción toma un mobile-agent-description como su parámetro. Mueve el agente identificado por los slots name y address del mobile-agent-description al lugar indicado en el slot destination. Mediante la ontología JADE, podemos añadir movilidad a los agentes sin tener que componer mensajes ACL. Para ello, en primer lugar, el agente debe crear un objeto de tipo MoveAction, rellenar sus argumentos con un MobileAgentDescription, que a su vez se rellenará con el nombre y dirección del agente que queremos mover (él mismo u otro agente) y con el objeto Location para el destino. Tras esto, con una simple llamada al método Agent.getContentManager().fillContent(…,…) podemos convertir el objeto MoveAction en un String y escribirlo dentro del slot content de un mensaje ACL request apropiado.
  • clone-agent. Es similar a la acción move-agent, pero en este caso tiene un argumento más de tipo String, en el que se pasa el nuevo nombre del agente que resulta del proceso de clonación.

El AMS también soporta otras acciones relacionadas con la movilidad y que están definidas en JADEManagementOntology:
  • where-is-agent. Solo tiene como argumento el AID del agente que se quiere localizar. Tiene como resultado el lugar del agente, que se coloca en el slot content del mensaje ACL inform.
  • query-platform-locations. Esta acción no toma argumentos. Su resultado es un conjunto de todos los objetos Location disponibles actualmente en la plataforma JADE.

Ejemplo: Guest
 /*
 * Ejecutar Guest en primer lugar.
 *
 */
package examples.Movilidad;
import java.util.*;
import java.io.*;
 
import jade.lang.acl.*;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.core.behaviours.*;
import jade.domain.*;
import jade.core.Runtime;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.core.*;
import jade.domain.JADEAgentManagement.*;
import jade.domain.mobility.*;
 
public class Guest extends Agent {
  private ArrayList containers = new ArrayList();
  private Location origen = null;
  private Location destino= null;
  private String partidaName= "", destinoName= "";
 
  protected void setup(){
    System.out.println("El agente " + (getAID()).getName() + " esta preparado");
    addBehaviour(new MoverAgenteBehaviour(this));
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil antes de desplazarse.
  protected void beforeMove(){
    System.out.println("El agente " + (getAID()).getName() + " se mueve al nuevo container");
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil despues de desplazarse.
  protected void afterMove() {
    //getContentManager().registerLanguage(new SLCodec());
    //getContentManager().registerOntology(MobilityOntology.getInstance());
    System.out.println("El agente " + (getAID()).getName() + " ha llegado");
  }
 
  class MoverAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public MoverAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() { }
 
    protected void takeDown(){
      System.out.println("El agente " + (getAID()).getName() + " termina");
    }
 
    public boolean done() {
      return parar;
    }
  }
}
 
Ejemplo: Host

/*
 * Ejecutar primero el agente Guest
 * Modificacion de los ejemplos disponibles en la pagina
 * http://www.iro.umontreal.ca/~vaucher/Agents/Jade/Mobility.html
 */
package examples.Movilidad;
import java.util.*;
import java.io.*;
 
import jade.lang.acl.*;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.core.behaviours.*;
import jade.domain.*;
import jade.core.Runtime;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.core.*;
import jade.domain.JADEAgentManagement.*;
import jade.domain.mobility.*;
 
public class Host extends Agent {
  private ArrayList containers = new ArrayList();
  private Location origen = null;
  private Location destino= null;
  private String partidaName= "", destinoName= "";
 
  //Metodo para actualizar la lista de containers disponibles
  protected void actualizarContainers(){
    containers.clear();
    ACLMessage request= new ACLMessage(ACLMessage.REQUEST);
    request.setLanguage(new SLCodec().getName());
    // Establecemos que MobilityOntology sea la ontologia de este mensaje.
    request.setOntology(MobilityOntology.getInstance().getName());
    // Le solicitamos al AMS una lista de los containers disponibles
    Action action= new Action(getAMS(), new QueryPlatformLocationsAction());
    try {
      getContentManager().fillContent(request, action);
      request.addReceiver(action.getActor());
      send(request);
 
      // Filtramos los mensajes INFORM que nos llegan desde el AMS
      MessageTemplate mt = MessageTemplate.and(MessageTemplate.MatchSender(getAMS()), MessageTemplate.MatchPerformative(ACLMessage.INFORM));
 
      ACLMessage resp= blockingReceive(mt);
      ContentElement ce= getContentManager().extractContent(resp);
      Result result=(Result) ce;
      jade.util.leap.Iterator it= result.getItems().iterator();
      // Almacena en el array los containers disponibles.
      while(it.hasNext()) {
    Location loc=(Location) it.next();
    containers.add(loc);
      }
    }catch(Exception ex) {
      ex.printStackTrace();
    }
  }
 
  //Metodo para visualizar los containers disponibles en la plataforma
  protected void verContainers(){
    //ACTUALIZAR
    //actualizarContainers();
    //VISUALIZAR
    System.out.println("******Containers disponibles: *******");
    for(int i=0; i<containers.size(); i++){
      System.out.println("["+ i + "] " + ((Location)containers.get(i)).getName());
    }
  }
 
  protected void setup(){
    // Registramos el lenguaje y la ontologia para la movilidad en el manejador del agente
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
 
    actualizarContainers();
    addBehaviour(new MoverAgenteBehaviour(this));
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil antes de desplazarse.
  protected void beforeMove(){
    System.out.println("[MSG] El agente se mueve al container: "+ destino.getName());
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil despues de desplazarse.
  protected void afterMove() {
    getContentManager().registerLanguage(new SLCodec());
    getContentManager().registerOntology(MobilityOntology.getInstance());
    System.out.println("[MSG] El agente ha llegado desde: "+ origen.getName());
  }
 
  class MoverAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public MoverAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() {
      try {
    verContainers();
    System.out.println();
    System.out.print("Introduce el numero del container al que mover: ");
    BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
    String lectura = lee.readLine();
    int container=0;
    if(lectura.equalsIgnoreCase("Q")){
      doDelete();
      return;
    }
    else{
      container = Integer.parseInt(lectura);
    }
    System.out.print("Introduce el nombre del agente que quieres mover: ");
    String nombre = lee.readLine();
 
 
    try{
      origen = here();
      destino=(Location)containers.get(container);
      ///////////////////////////////////////////////
      AID aid = new AID(nombre, AID.ISLOCALNAME);      //"movil", AID.ISLOCALNAME);
      MobileAgentDescription mad = new MobileAgentDescription();
      mad.setName(aid);
      mad.setDestination(destino);
      MoveAction ma = new MoveAction();
      ma.setMobileAgentDescription(mad);
      sendRequest(new Action(getAMS(), ma));
    }catch(Exception ex){
      System.out.println("Problema al intentar mover el agente");
    }
      }catch(Exception io){
    System.out.println(io);
      }
    }
 
    public boolean done() {
      return parar;
    }
  }
 
  protected void takeDown(){
    System.out.println("[MSG] Agente finalizado");
  }
 
  void sendRequest(Action action) {
    // ---------------------------------
    ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
    request.setLanguage(new SLCodec().getName());
    request.setOntology(MobilityOntology.getInstance().getName());
    try {
      getContentManager().fillContent(request, action);
      request.addReceiver(action.getActor());
      send(request);
    }catch (Exception ex) { ex.printStackTrace(); }
   }
 
}
 




Nota: Los ejemplos son modificaciones del código que se encuentra en http://www.iro.umontreal.ca/~vaucher/Agents/Jade/Mobility.html

5.5 Ejercicios


A hacer:
  • Enviad el ejercicio de codificación completado y las respuestas de las preguntas a la dirección de correo arenteiro.sma@gmail.com indicando:
    • Nombre y apellidos.
    • D.N.I.
    • Grupo.

PARTE I

  • Responder a las siguientes cuestiones:
    • ¿Qué tipo o tipos de movilidad soporta JADE?
    • ¿Qué parámetro necesitan los métodos doMove y doClone? ¿Por qué?
    • ¿Qué consideras mejor mover o clonar? ¿Por qué?


PARTE II

  • Con la ayuda de los ejemplos realizados anteriormente completar el código del siguiente ejercicio. El funcionamiento consiste en que el agente pregunte al usuario que desea, que se mueva o clone, y posteriormente pregunte a donde y el nombre si es necesario.
package examples.Movilidad;
import java.util.*;
import java.io.*;
 
import jade.lang.acl.*;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import ....................
...........................
...........................
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
..........................
..........................
..........................
 
public class AgenteMC extends Agent {
  private ArrayList containers = new ArrayList();
  private Location origen = null;
  private Location destino= null;
  private String mensaje = "";
  private boolean movido = false;
 
  //Metodo para actualizar la lista de containers disponibles
  protected void actualizarContainers(){
    origen = here();
    containers.clear();
    ...............................................
    request.setLanguage(new SLCodec().getName());
    // Establecemos que MobilityOntology sea la ontologia de este mensaje.
    ...............................................
    // Le solicitamos al AMS una lista de los containers disponibles
    Action action= new Action(getAMS(), ................................);
    try {
      getContentManager().fillContent(request, action);
      request.addReceiver(action.getActor());
      send(request);
 
      // Filtramos los mensajes INFORM que nos llegan desde el AMS
      MessageTemplate mt= MessageTemplate.and(MessageTemplate.MatchSender(getAMS()), MessageTemplate.MatchPerformative(ACLMessage.INFORM));
 
      ACLMessage resp= blockingReceive(mt);
      ContentElement ce= getContentManager().extractContent(resp);
      Result result=(Result) ce;
      jade.util.leap.Iterator it= result.getItems().iterator();
      // Almacena en un ArrayList "Locations" de los "Containers" a los que puede moverse el agente movil.
      while(it.hasNext()) {
    .......................
        .......................
      }
    }catch(Exception ex) {
      ex.printStackTrace();
    }
  }
 
  //Metodo para visualizar los containers disponibles en la plataforma
  protected void verContainers(){
    //ACTUALIZAR
    actualizarContainers();
    //VISUALIZAR
    System.out.println("******Containers disponibles: *******");
    for(int i=0; i<containers.size(); i++){
      System.out.println("["+ i + "] " + ((Location)containers.get(i)).getName());
    }
  }
 
  protected void setup(){
    // Registramos el lenguaje y la ontologia para la movilidad en el manejador del agente
    try{
        boolean Noleido=true;
        getContentManager().registerLanguage(new SLCodec());
        getContentManager().registerOntology(MobilityOntology.getInstance());
        String lectura="";
        int accion=0;
        do{
            System.out.println("Introduzca que deasea hacer: ");
            System.out.println("[1]. Mover");
            System.out.println("[2]. Clonar");
            BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
            lectura = lee.readLine();
            accion = Integer.parseInt(lectura);
            if ((accion==1)||(accion==2)){
                Noleido=false;
            }
        }while(Noleido);
        if (accion==1){
            actualizarContainers();
            ......................................
        }else{
            movido=true;
            actualizarContainers();
            .......................................
        }
    }catch(Exception ex){
      System.out.println("Problema en el setup");
    }
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil antes de desplazarse.
  protected void beforeMove(){
    System.out.println("El agente se marcha o clona");
  }
 
  // Metodo que contiene las operaciones que realiza el agente movil despues de desplazarse.
  protected void afterMove() {
    .........................................................
    .........................................................
    System.out.println("[MSG] El agente ha llegado desde: "+ origen.getName());
    leerArchivo();
    System.out.println(mensaje);
    if(movido == false){
      movido = true;
      System.out.println("El agente esta leyendo el fichero");
      leerArchivo();
      for(int i=0; i<5; i++){
        System.out.print(".");
        doWait(1000);
      }
      doMove(origen);
    }
  }
 
  class MoverAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public MoverAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() {
      try {
    verContainers();
    System.out.print("Introduce el numero del container al que mover: ");
    BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
    String lectura = lee.readLine();
    int container = Integer.parseInt(lectura);
 
    try{
      ......................................
      // Metodo al que llama el agente para desplazarse a su nuevo destino.
      ......................................
    }catch(Exception ex){
      System.out.println("Problema al intentar mover el agente");
    }
      }catch(IOException io){
    System.out.println(io);
      }
      parar = true;
    }
 
    public boolean done() {
      return parar;
    }
  }
 
    class ClonarAgenteBehaviour extends SimpleBehaviour {
    private boolean parar= false;
 
    public ClonarAgenteBehaviour(Agent a) {
      super(a);
    }
 
    public void action() {
      try {
    verContainers();
    System.out.print("Introduce el numero del container en el que clonar: ");
    BufferedReader lee= new BufferedReader(new InputStreamReader(System.in));
    String lectura = lee.readLine();
    int container = Integer.parseInt(lectura);
    System.out.print("Introduce el nombre del clon: ");
    String nombre = lee.readLine();
 
    try{
      origen = here();
      ..........................................
 
      // Metodo al que llama el agente para desplazarse a su nuevo destino.
      // Este destino es de tipo "Location".
      ...........................................
 
    }catch(Exception ex){
      System.out.println("Problema al intentar clonar el agente");
    }
      }catch(IOException io){
    System.out.println(io);
      }
    }
 
    public boolean done() {
      return parar;
    }
  }
  protected void takeDown(){}
 
  private void leerArchivo(){
    File archivo = null;
    FileReader fr = null;
    try {
      archivo = new File ("fichero.txt");
      if(archivo.exists()){
    String linea;
    fr = new FileReader (archivo);
    BufferedReader br = new BufferedReader(fr);
    while((linea=br.readLine())!=null)
      mensaje = linea;
      }
    }
    catch(IOException e){
      System.out.println(e);
    }
  }
}
 

5.5 Ejercicios 2013


La solución a la práctica deberá enviarse al mail rfpuga@esei.uvigo.es indicando:

Nombre y apellidos:
D.N.I:
Grupo:

Para realizar la práctica se darán 4 ficheros de partida:

Empleado.java
Supervisor.java
Jefe.java
Ordenador.java

Se tienen que completar los ficheros facilitados para poder realizar las siguientes acciones:

1) Crear los agentes cada uno en su container en el siguiente orden: Empleado, Supervisor, Jefe, Ordenador

2) Mover desde el terminal del Supervisor dicho agente al container de los empleados

3) Mover desde el terminal del Jefe el agente Empleado al antiguo container del Supervisor (vacío en este paso)

4) Clonar el agente Ordenador en los 3 containers restantes con los nombres: OrdenadorEmpleado, OrdenadorSupervisor, OrdenadorJefe según corresponda

5) Comprobar que en los terminales de dichos containers aparezca el mensaje "Departamento listo para trabajar"

Será necesario incluir en la solución una captura de pantalla de la gui de Jade para comprobar que todos los pasos se han realizado correctamente. Para facilitar la realización de la práctica se proporciona una carpeta adicional con ejemplos.