Académique Documents
Professionnel Documents
Culture Documents
set PATH=%PATH%;Directorio_Instalación_Java\bin
Los binarios de Jade-2.61 han sido desarrollados con el JDK-1.2 pero también han sido probados
con el JDK-1.3. Los ejemplos de este documento se probaron con la versión JDK-1.4.1_01. Se pueden
descargar de la dirección http://sharon.cselt.it/projects/jade/. Además es posible obtener en esta
dirección los fuentes, documentación y ejemplos de aplicación.
En nuestra instalación actual, la máquina tendrá una instalación de Jade en el directorio C:\Jade-
2.61. Este directorio será referenciado en el resto de l documento como JADE. Colgando del directorio
JADE tenemos cuatro subdirectorios:
1. demo. Ejemplo de uso de Jade. Ficheros para la ejecución y de explicación.
2. doc. Documentación de Jade. Incluye la API y manuales de programación, administración,
ontologías y seguridad. También hay una explicación de los ejemplos contenidos en el
subdirectorio src\examples.
3. lib. Jar de Jade.
4. src. Contiene dos subdirectorios, demo y examples, El primero contiene los fuentes
correspondientes al ejemplo en el directorio demo del punto 1. El segundo contiene los fuentes
de varios ejemplos más simples con Jade.
Instalación.
Para poder trabajar con Jade es necesario hacer disponibles las correspondientes librerías. Los
sistemas multiagente se componen de múltiples elementos, los agentes. Aunque en la mayor parte de este
tutorial se empleará un IDE gráfico puede ser necesario arrancar agentes desde la línea de comandos. Para
hacer disponibles las librerías desde la línea de comandos del sistema operativo hay que hacer:
prompt> set
CLASSPATH=%CLASSPATH%;JADE\lib\jade.jar;JADE\lib\jadeTools.jar;J
ADE\lib\Base64.jar;JADE\lib\iiop.jar;.
En el caso de un IDE gráfico, nuestro proyecto tendría que tener disponibles las librerías
señaladas en la línea anterior jade.jar, jadeTools.jar, Base64.jar y iiop.jar.
Es posible inicializar contenedores en otras plataformas con la opción host. Para no sobrecargar
la máquina con IDE’s es recomendable que al menos la plataforma se arranque desde la línea de
comandos.
donde AgentSpecifier list es una secuencia de strings separados por espacios. Cada string es de la forma
NombreAgente:ClaseAgente(Argumentos)
donde:
NombreAgente es el nombre del agente en la plataforma.
ClaseAgente es el nombre cualificado de la clase que implementa el agente. El contenedor
cargará dinámicamente esta clase.
Argumentos es la lista de argumentos que se pasan al agente en su creación.
Nota: Los ejemplos son suministrados como fuentes, por tanto es necesario compilarlos previamente.
Es posible arrancar los agentes desde la plataforma aunque esto se explicará en el próximo
apartado. En algunas instalaciones, la necesidad de la plataforma de establecer comunicaciones con los
agentes puede entrar en conflicto con las políticas del sistema. En este caso se hace necesario el arranque
de los agentes desde la plataforma.
Herramientas de Jade.
Jade incluye varias herramientas que simplifican la administración de la plataforma y el
desarrollo de aplicaciones. Cada herramienta está contenida en un paquete separado de jade.tools.
Las herramientas disponibles en la actualidad son:
• Remote Management Agent, RMA. Es una consola gráfica para la administración y el control de
la plataforma. En la sección Arranque de este documento se indica como iniciar una primera
instancia del RMA y su aspecto. Es posible activar varios RMAs. En este caso, Jade mantiene la
coherencia entre ellas enviando los eventos a todas. Desde esta consola se pueden arrancar el
resto de las herramientas de Jade. Las plataformas aparecen en el RMA con un icono de carpetas
amarillas, los contenedores dentro de los RMA’s como carpetas verdes y dentro de los
contenedores aparecen los agentes con el icono de cabezas. Para arrancar un agente desde el
RMA hay que seleccionar previamente un contenedor. Presionando el botón derecho surge un
menú emergente una de cuyas opciones es Start New Agent. Esta opción abre un cuadro de
diálogo donde se solicita el nombre del agente, su clase y los argumentos. Siguiendo el ejemplo
del apartado anterior, el nombre del agente sería Sender1, su clase
examples.Receivers.AgentSender y no tendría argumentos.
• IntrospectorAgent. Permite monitorizar el ciclo de vida de los agentes y los mensajes ACL que
intercambian.
• Sniffer. Es un agente que intercepta los mensajes ACL lanzados y los visualiza gráficamente en
un modo similar a los diagramas de secuencia de UML. Resulta útil para depurar conversacioens
entre agentes.
Estas herramientas son las empleadas habitualmente en el desarrollo de los sistemas multiagente
con Jade. Otras herramientas que también se incluyen son el SocketProxyAgent y el DF GUI que es una
interfaz gráfica para el DF (Directory Facilitator) por defecto de Jade.
Identificadores de agentes.
Para realizar comunicaciones entre agentes es necesario que estos estén identificados de forma
única en la plataforma. De acuerdo con las especificaciones de FIPA, cada agente posee un Identificador
de Agente (AID = Agent Identifier). La estructura del AID se compone de varios campos, siendo los más
importante los de nombre y dirección. El nombre del agente es un identificador global único para él.
JADE construye dicho identificador concatenando el nombre dado al agente en la plataforma por el
usuario con el nombre de la plataforma inicial del agente (HAP = Home Agent Platform) separa dos por el
carácter ‘@’. Un ejemplo de este nombre sería peter@kim:1099/JADE, donde “peter” es el
nombre del agente y “kim:1099/JADE”el de la plataforma. Sólo los nombres completos son válidos
dentro de los mensajes ACL. Las direcciones por el contrario pueden contener varias direcciones de
transporte en las cuales contactar al agente. La sintaxis de estas direcciones es una secuencia de URI.
FIPA incorpora en su plataforma el AMS (Agent Management System) que es el agente que
supervisa el acceso y uso de la plataforma de agentes. Sólo existe un AMS por plataforma. El AMS es el
encargado de proporcionar los servicios de páginas blancas y de ciclo de vida para los agentes y de
mantener el directorio de los AIDs de los agentes y su estado. Cada agente debe registrarse con el AMS
para obtener un AID válido. El DF (Directory Facilitator) es el agente que proporciona el servicio de
páginas amarillas. El ACC (Agent Communication Channel) es el software que controla el intercambio de
mensajes, tanto dentro de la plataforma como con otras remotas.
Agentes de Jade.
Para explicar los principales conceptos manejados por los agentes de Jade vamos a basarnos en
los agentes de ejemplo empleados anteriormente (directorio examples/receivers).
Definimos un proyecto IRAgents en nuestro IDE y le incluimos las librerías de Jade. Creamos
una nueva clase dentro del paquete IRAgents llamada AgentSender que es una instancia de
jade.core.Agent. La clase jade.core.Agent representa la base común para todos los agentes
de Jade. La herencia de esta clase le proporciona la capacidad de realizar las interacciones básicas con la
File AgentSender.java
package iragents;
import jade.core.Agent;
El agente tiene un método setup que debe emplearse para la inicialización del agente. Este
método se ejecuta después de la inicialización relacionada con la plataforma. Es por tanto aquí donde
comienza el comportamiento definido por el usuario.
Los agentes de Jade se implementan con un único thread de ejecución. Las diferentes tareas que
realiza un agente se han de encapsular en comportamientos que heredan de la clase
jade.core.behaviours.Behaviour. Para gestionar los comportamientos de un agente la clase
Agent tiene los métodos addBehaviour y removeBehaviour. Los comportamientos pueden ser
añadido y eliminados en cualquier momento de la vida del agente. Existen varias subclases de
Behaviour predefinidas. Los dos métodos principales que debe definir un Behaviour son action y
done. Un planificador implementado por la clase Agent y oculto al programador selecciona el
Behaviour a ejecutar según un round-robin entre los Behaviour preparados. El Behaviour lleva a
cabo su tarea con el método action. El método action es invocado cuando tiene lugar el evento
asociado al Behaviour. Este evento puede ser la llegada de un mensaje o una temporización por
ejemplo. La aproximación a la planificación hecha por Jade, recomienda que los métodos action no
tengan un tiempo de ejecución alto ya que mientras que se ejecutan no pueden ser interrumpidos por otro
comportamiento. Cuando termina el método action, se invoca al método done para saber si ha
terminado su tarea. En caso de que no haya terminado queda reprogramado para la siguiente ronda. Para
poder usarlos añadimos importamos los paquetes:
import jade.core.*;
import jade.core.behaviours.*;
addBehaviour(new SimpleBehaviour(this) {
public void action() {
}
public boolean done(){
return true;
}
}); /* Behaviour class end */
Queremos que el agente sea capaz de enviar una petición a un servidor. Para ello se emplea un
lenguaje de comunicación de agentes (ACL). La clase jade.lang.acl.ACLMessage representa los
mensajes ACL intercambiados por los agentes. Esta clase contiene una serie de atributos definidos por los
estándares de FIPA como emisor, receptor y contenido. Estos atributos pueden ser accedidos por medio
de los métodos set/get<Attribute> y add/getAll<Attribute> para aquellos atributos
que son conjuntos. Los mensajes son gestionados a través de una cola de mensajes que es única para el
agente y, por tanto, es compartida por todos los comportamientos. Añadimos a las importaciones:
import jade.lang.acl.*;
try{
System.out.println("\nEnter responder agent name: ");
BufferedReader buff = new BufferedReader(new
InputStreamReader(System.in));
String responder = buff.readLine();
ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
msg.addReceiver(new AID(responder));
msg.setContent("FirstInform");
send(msg);
System.out.println("\nFirst INFORM sent");
finished = true;
myAgent.doDelete();
}catch (IOException ioe){
ioe.printStackTrace();
}
Los agentes pueden enviar mensajes mediante el método send y recibirlos con los métodos
receive y blockingReceive. El método doDelete es invocado para finalizar la ejecución del
agente. Hemos introducido una variable a nivel del comportamiento para controlar la finalización del
mismo. Por ello cambiamos el método done a:
Con este código queda completo el cliente. El servidor tiene la misma estructura básica.
File AgentReceiver.java
package iragents;
import java.io.*;
import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
Como comportamiento del agente crearemos una nueva clase cuyo método action es un
ejemplo de como descomponer una tarea con una máquina de estados evitando un tiempo de ejecución
demasiado largo. El código es:
import jade.lang.acl.MessageTemplate;
Los agentes han de ser capaces de mantener varias conversaciones simultáneas, sin embargo la
cola de mensajes es compartida por todos los comportamientos. Por ello se define la clase
jade.lang.acl.MessageTemplate que construye patrones contra los que comprobar los atributos
de los mensajes ACL. Estos patrones pueden ser combinados con los operadores AND, OR y NOT.
Añadimos un nuevo método op1.
El template se pasa como argumento al método receive que lo usa como patrón.
if (msg!= null){
System.out.println("\nAgent "+ getLocalName() +
" received the following message in state 1.1: " +
msg.toString());
return true;
}
else {
System.out.println("\nNo message received in state 1.1");
block();
return false;
}
}
Modificamos el action del comportamiento para que utilice este nuevo método.
Construir manualmente las ontologías de este modo resulta muy tedioso. Para automatizar la
tarea, la Universiteit van Amsterdam ha desarrollado el Ontology Bean Generator
(http://gaper.swi.psy.uva.nl/beangenerator/content/main.php). A partir de una ontología
desarrollada con Protégé, el Bean Generator genera las clases necesarias para su manejo desde Jade.
El soporte de Jade para ontologías incluye las clases para trabajar con estas y con los lenguajes
de contenido. Los lenguajes de contenido tienen que ver con la representación interna del contenido de los
mensajes ACL. Las ontologías tienen que ver con la semántica de los mensajes que se intercambian y su
chequeo.
El uso de una ontología generada por Protégé desde Jade requiere incluir la librería
beangenerator.jar.
Para que un agente de Jade use una ontología debe importarla y registrarla. Luego la utilizará con
la API correspondiente de Jade. En primer lugar hay que importar los paquetes de soporte de Jade y las
clases Java que representan la ontología. En nuestro caso la ontología es
ucm.dsip.ontology.Viviendas:
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.content.onto.*;
import ucm.dsip.ontology.*;
Para almacenar en el agente los datos de la ontología y los codecs definimos dos atributos y los
inicializamos:
Con los atributos inicializados queda por asociar la ontología y el codec con sus nombres. Esta
asociación se realiza a través del ContentManager que forma parte del soporte de Jade para las
ontologías. Las instrucciones a emplear son:
getContentManager().registerLanguage(codec);
getContentManager().registerOntology(ontology);
msg.setContent("Piscina");
En el AgentReceiver debemos insertar las líneas que vimos previamente para registrar la
ontología de Viviendas. Los conceptos de la ontología son representados por Schema. Para obtener el
Schema asociado a un string usamos el método getSchema de la ontología. Los Schema son
implementados por las clases Java generadas para la ontología. El modo de obtener un objeto Java
asociado a un Schema es con el método toObject de la ontología. El código para buscar el concepto
asociado al contenido del mensaje en la ontología quedaría en el método op1 como sigue:
try {
if (ontology.getSchema(msg.getContent()) != null) {
Class contentClass =
ontology.toObject(ontology.getSchema(msg.getContent()).newInstance()).getClass();
System.out.println("\nConcept " + msg.getContent() +
" has Schema " + ontology.getSchema(msg.getContent()) +
" which is represented by Java class " + contentClass.getName() +
"\n\n");
} else
System.out.println("\nConcept " + msg.getContent() +
" is not in the ontology.\n\n");
} catch(OntologyException e) {
System.out.println("st.nextToken() unsuccessful");
}