sábado, 29 de marzo de 2008

Manejo de comportamientos en JADE

Las tareas o servicios que un agente hace se especifican a través de comportamientos. Un comportamiento (behaviour) hace referencia a una funcionalidad que incorpora el agente. Para que un agente pueda crear uno o más comportamientos debe heredar la clase jade.core.behaviours.Behaviour. Una vez que se ha implementado, el agente puede ejecutar ese comportamiento cada vez que sea invocado dentro del método setup del agente, el cual los anexa al agente a través del metodo addBehaviour perteneciente a la clase Agent.
Se puede pensar que los comportamientos son como los hilos de ejecución en Java (threads), ya que al igual que estos, en un agente pueden ejecutarse a la vez tantos comportamientos como sea necesario. Sin embargo, a diferencia de los hilos, el decidir que comportamiento se ejecuta en cada momento es tarea del desarrollador del agente. Esto es así para que cada agente sea equivalente únicamente a un único hilo, con el consiguiente ahorro de ciclos de CPU y memoria que esto implica.
La creación de los comportamientos se realiza extendiendo la clase jade.core. Behaviours, para lo cual la clase Agent tiene dos métodos para poder agregar o eliminar comportamientos:
  • addBehaviour
  • removeBehaviour

Estos comportamientos pueden ser anexados dentro del método setup (lo habitual), desde cualquier comportamiento, o desde otros agentes. Algunos métodos con los que cuentan los comportamientos son:

  • action: Método que implementa la tarea a realizar.
  • done: Método booleano que comprueba si la tarea ha acabado, eliminándola si retorna true.
  • block: Método que bloquea la ejecución del comportamiento. El bloqueo se hace efectivo cuando el método action retorna, el cual puede ser configurado con un determinado tiempo.
  • restar: Se reinicia explícitamente un comportamiento bloqueado.
  • reset: Retorna el comportamiento a su estado inicial.
  • onStart: Acciones antes de iniciar el comportamiento.
  • onEnd: Acciones antes de finalizar el comportamiento.

JADE no guarda el estado de los comportamientos, razón por la cual es responsabilidad del desarrollador guardar el último estado de este.

Los comportamientos pueden ser agrupados en tres grandes grupos:

  • Comportamientos one-shot: Son aquellos que se ejecutan de manera casi instantánea, y solamente una vez.
  • Comportamientos cíclicos: Son aquellos que nunca son sacados del conjunto de comportamientos del agente y cuyo método action siempre ejecuta el mismo código. Por lo tanto, nunca finalizan.
  • Comportamientos genéricos: Un poco más complejos ya que el código que se ejecuta en ellos depende del estatus del agente, y eventualmente analizan su ejecución.

Otro tipo de comportamientos en JADE son los compuestos, que permiten combinar comportamientos previamente definidos de manera conveniente para aplicarles un orden de ejecución determinado; estos son:

  • Secuenciales a través de SequentialBehaviour.
  • En paralelo a través de ParallelBehaviour.
  • Guiados mediante un autómata finito deterministico a través de FSMBehaviour.

Existen comportamientos a los cuales se les puede definir su ejecución a través de un tiempo de espera; estos son WakerBehaviour y TickerBehaviour, los cuales tienen en común que su ejecución es diferida. Se invocan y aguardan hasta que se ha cumplido un determinado tiempo. El primero de estos solamente se ejecuta una vez y el segundo es un comportamiento cíclico.

Los objetos behaviour describen pequeñas tareas que debe realizar el agente ejecutándose según un planificador que se encuentra implementado en la clase Agent. El planificador va ejecutando según una política round-robin (o por turnos rotatorios) de los objetos behaviour que se encuentran en una cola FIFO.

Los objetos behaviour tienen dos métodos que se deben reescribir, action() y done(). El método action() es en donde se deben desarrollar las tareas que debe realizar el agente, mientras que el método done() es llamado cuando el action() finaliza. El planificador va ejecutando uno a uno los métodos action() de la cola y cuando el método action() de un objeto finaliza se llama al método done(), el cual debe retornar un valor booleano. Si retorna true, el objeto es sacado fuera del planificador ya que se da por concluida su tarea, mientras que si retorna false se vuelve a planificar.

Si en algún momento de la ejecución del método action() se requiere esperar por la llegada de un mensaje, existe el método block() para mandar a una cola de bloqueados cuando el método action() finaliza (no cuando se llama a block()). Cuando se produce la llegada de un mensaje, todos los objetos en la cola de bloqueados se planifican y deben comprobar si el mensaje llegado es para ellos o no. En caso de que un objeto no sea el destinatario del mensaje este debe volver a bloquearse.

Es importante que los métodos action() sean cortos, de esta forma se permite un cierto grado de paralelismo. Si se necesita realizar una tarea que va a requerir un largo periodo de tiempo, entonces el desarrollador deberá dividir la tarea en subtareas y cada una de ellas implementarla mediante un objeto behaviour. Con el fin de ayudar en esta labor, JADE proporciona una jerarquía de clases behaviour, que permite incluso simular maquinas de estados finitos.

  • SimpleBehaviour: Representa un comportamiento atómico.
  • OneShotBehaviour: Representa un comportamiento que se debe ejecutar solo una vez, por eso su método done() retorna true, si no es redefinido.
  • CyclicBehaviour: Representa un comportamiento que debe ejecutarse una serie de veces. El método done, si no es redefinido, devuelve false.
  • SenderBehaviour: Encapsula la acción de envió de un mensaje ACL. Este mensaje debe ser especificado en el constructor.
  • ReceiverBehaviour: Encapsula la acción de recepción de un mensaje ACL. Termina cuando se recibe el mensaje o cuando pasa una cierta cantidad de tiempo especificada en el constructor.
  • WakerBehaviour: Implementa un comportamiento OneShot que se ejecuta justo después de que haya pasado un tiempo especificado.
  • CompositeBehaviour: Esta clase se compone de diferentes sub-behaviours que se pueden ejecutar siguiendo diferentes políticas de planificación, las cuales vienen determinadas por la subclase elegida, las que pueden ser: SequentialBehaviour, ParallelBehaviour y FSMBehavior.
  • SequentialBehaviour: Esta clase deriva de CompositeBehaviour y ejecuta sub-behaviours de forma secuencial, y termina cuando todos los métodos action() han terminado.





  • ParallelBehaviour: Esta clase deriva de CompositeBehaviour y ejecuta los sub-behaviours de manera concurrente. En el constructor de la clase se puede especificar cuando se desea que acabe la ejecución: cuando todos los sub-behaviours lo han hecho, cuando uno termine, o cuando un numero especificado lo logre.





  • FSMBehaviour: Esta clase permite definir una maquina de estados finita mediante sub-behaviours. Cada sub- comportamiento representa un estado de la maquina, y las transiciones se van produciendo según la salida de dichos estados. La finalización se alcanza cuando se termine de ejecutar algún sub-behaviour que se haya registrado como estado final.


Adjunto dos codigos de ejemplo para que vean lo facil que es agregar comportamientos a un agente.

En el proximo post veremos mensajeria y ACL.



No hay comentarios: