4. Ontologías - Lenguajes de contenido

4.1 Introducción

4.2 Definición de una ontología

4.3 Desarrollo de clases de una ontología

4.4 Selección de un lenguaje de contenido

4.5 Registro de una ontología y de un lenguaje de contenido

4.6 Ejercicios


4.1 Introducción


La RAE define el término ontología como la “parte de la metafísica que trata del ser en general y de sus propiedades trascendentales”. Sin embargo, en el campo de la informática, “no ha de ser considerada como una entidad natural que se descubre sino como un recurso artificial que se crea” (Mahesh, 1996).

El sinónimo más habitual de ontología es conceptualización:

  • Modelo abstracto de algún fenómeno del mundo del que se identifican los conceptos que son relevantes.
  • Hace referencia a la necesidad de especificar de forma consciente los distintos conceptos que conforman una ontología.
  • Indica que la especificación debe representarse por medio de un lenguaje de representación formalizado.
  • Refleja que una ontología debe, en el mejor de los casos, dar cuenta de conocimiento aceptado, como mínimo, por el grupo de personas que deben usarla.

Una Ontología es la "especificación de una conceptualización", la descripción de los conceptos y relaciones entre ellos, que pueden formar parte del conocimiento de un agente o una sociedad de agentes.

La necesidad de utilizar ontologías viene dada por la complejidad inherente a las aplicaciones desarrolladas en el contexto de los Sistemas Multi-Agente, que hace que se presenten las siguientes dificultades:

  • Abundancia de comunicación entre agentes.
  • Interoperabilidad de sistemas y plataformas.
  • Problemas semánticos.

Para que los agentes se comuniquen entre ellos, deben compartir el mismo idioma, vocabulario y protocolos. Al seguir las recomendaciones del estándar FIPA, JADE ya aporta un cierto grado de coincidencia al usar los actos comunicativos FIPA y su lenguaje de contenido SL (Semantic Language), que determinan la forma en que los mensajes son intercambiados por los agentes. Sin embargo, será necesario definir ontologías específicas, con su propio vocabulario y semántica del contenido de los mensajes intercambiados por los agentes.

JADE proporciona tres formas distintas de llevar a cabo la comunicación entre agentes:

  1. La forma más básica es utilizar cadenas para representar el contenido de los mensajes. Esto es conveniente cuando el contenido de los mensajes son datos atómicos pero no en el caso de conceptos abstractos, objetos o datos estructurados, ya que en estos casos, se tendrían que realizar parseos sobre las cadenas para acceder a sus diversas partes.
  2. Otra forma es utilizar objetos serializables de Java, que transmitirían directamente el contenido de los mensajes. Este es el método más conveniente para aplicaciones locales donde todos los agentes son implementados en Java. Un inconveniente es que estos mensajes no son entendibles para las personas.
  3. El tercer método consistiría en definir los objetos que van a ser transferidos como extensión de las clases predefinidas por JADE que pueden codificar/decodificar los mensajes a un formato FIPA estándar. Esto permite que los agentes de JADE puedan interoperar con otros sistemas de agentes.

Una ontología en JADE, se define de forma que los agentes se comuniquen utilizando el tercer método descrito. El soporte JADE para ontologías incluye las clases para trabajar con éstas 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.

graficaACL.JPG

Es decir, mediante el uso de ontologías incorporamos contenido semántico, y no sólo datos, como hasta ahora, a los mensajes que se intercambian los agentes. Pero teniendo en cuenta que las ontologías se definen en base a objetos de Java, necesitamos un modo de encapsular o codificar la semántica de esos objetos dentro de mensajes ACL, y hacer el proceso contrario, de descodificación, en la recepción del mensaje. Con ese propósito llegamos a los lenguajes de contenido (LEAP y SL) y todo el soporte Jade para el manejo de ontologías.

Conversión realizada por el soporte de Jade para ontologías.

Jade incorpora, en el paquete jade.content, soporte (codecs), para dos lenguajes de contenido:
  • El lenguaje SL es legible por los humanos y codifica las expresiones como string.
  • El lenguaje LEAP no es legible por los humanos y es byte-encoded.

Una ontología es una instancia de la clase jade.content.onto.Ontology en la cual se definen los Schemas, conjuntos de elementos que definen la estructura de los predicados, las acciones de los agentes y conceptos relevantes al dominio del problema.
  • Predicados: expresiones sobre el estado de mundo. Se utilizan típicamente en mensajes INFORM y QUERY-IF, no en REQUEST.
  • Acciones de los agentes: expresiones que indican acciones que pueden realizar los agentes. Típicamente se utilizan en mensajes de tipo REQUEST.
  • Conceptos: expresiones que representan objetos, representan una estructura con varios atributos. No aparecen aislados en los mensajes sino incluidos en otros elementos.
  • Otros elementos: primitivas (elementos atómicos como números o cadenas de caracteres), agregaciones (conjuntos, listas de otros términos), expresiones (identifican las entidades para las que se cumple un predicado), variables.

Los esquemas son instancias de las clases PredicateSchema, AgentActionSchema y ConceptSchema incluidas en el paquete jade.content.schema. Para cada uno de los elementos que definamos en la ontología se deberá de crear una clase asociada.




graficaJADE.GIF
Modelo de contenido de JADE


arriba.png

4.2 Definición de una ontología


Una ontología en JADE es una instancia de la clase jade.content.onto.Ontology, en la que se añaden los esquemas que definen la estructura de los tipos de predicados, acciones y conceptos relevantes en el dominio en cuestión. Estos esquemas son instancias de las clases PredicateSchema, AgentActionSchema y ConceptSchema, que se incluyen en el paquete jade.content.schema.

Estas clases tienen métodos para poder declarar slots que definen la estructura de cada tipo de predicado, acción y concepto. Como una ontología es básicamente una colección de esquemas que normalmente no varían a lo largo del ciclo de vida de un agente, es recomendable declarar la ontología siguiendo el patrón singleton, de modo que sólo se pueda crear un objeto de esa clase. Esto nos permite compartir la misma ontología (y todos los esquemas incluídos) entre todos los agentes que se estén ejecutando en la JVM.

Supongamos una ontología para una tienda de frutas, que podemos utilizar para enviarse ofertas entre agentes.

Podemos identificar los diferentes tipos de esquemas de una ontología:
  • Conceptos: representan las entidades que forman parte de la ontología, en este caso la ontología tendrá un concepto que será “Frutas”.

  • Predicados: son expresiones que relacionan a los conceptos para decir algo. Son necesarios porque en un mensaje nunca podremos enviar conceptos, sino que tendremos que enviar predicados o acciones. En el ejemplo usaremos un predicado “Oferta” que indicará que un agente oferta una determinado fruta.

  • Acciones: son acciones que pueden llevar a cabo los agentes. Para la ontología de frutas una acción será “Comprar” que indicará a un agente que debe comprar una determinada fruta.

FrutasOnto.png

Una vez identificada la estructura de la ontología, la definimos en Jade del siguiente modo:
package examples.frutasOntology;
 
import jade.content.onto.*;
import jade.content.schema.*;
 
public class frutasOntology extends Ontology {
   // Nombre de la ontología
   public static final String ONTOLOGY_NAME = "ontología de frutas";
 
  // Vocabulario de la ontología que van a manejar los agentes
  public static final String FRUTA = "Fruta";
  public static final String FRUTA_NOMBRE = "nombre";
  public static final String FRUTA_PRECIO = "precio";
 
  public static final String OFERTA = "Oferta";
  public static final String OFERTA_FRUTA = "fruta";
 
  public static final String COMPRAR = "Comprar";
  public static final String COMPRAR_FRUTA = "fruta";
 
  // Instancia de la ontología (que será única)
  private static Ontology instancia = new frutasOntology();
 
  // Método para acceder a la instancia de la ontología
  public static Ontology getInstance() {
     return instancia;
   }
 
   // Constructor privado
   private frutasOntology() {
     // frutasOntology extiende la ontología básica
     super(ONTOLOGY_NAME, BasicOntology.getInstance());
 
     try {
       // Añade los elementos
       add(new ConceptSchema(FRUTA), Fruta.class);
       add(new PredicateSchema(OFERTA), Oferta.class);
       add(new AgentActionSchema(COMPRAR), Comprar.class);
 
       // Estructura del esquema para el concepto FRUTA
       ConceptSchema cs = (ConceptSchema) getSchema(FRUTA);
       cs.add(FRUTA_NOMBRE, (PrimitiveSchema) getSchema(BasicOntology.STRING));
       cs.add(FRUTA_PRECIO, (PrimitiveSchema) getSchema(BasicOntology.INTEGER));
 
       // Estructura del esquema para el predicado OFERTA
       PredicateSchema ps = (PredicateSchema) getSchema(OFERTA);
       ps.add(OFERTA_FRUTA, (ConceptSchema) getSchema(FRUTA));
 
       // Estructura del esquema para la acción COMPRAR
       AgentActionSchema as = (AgentActionSchema) getSchema(COMPRAR);
       as.add(COMPRAR_FRUTA, (ConceptSchema) getSchema(FRUTA));
     }
     catch (OntologyException oe) {
       oe.printStackTrace();
     }
   }
}
 

Podemos observar que lo primero que se hace es definir el nombre de la ontología, y un vocabulario que será el que manejen los agentes para comunicarse. A continuación, se definen y se añaden los elementos a la ontología. Para cada elemento de la ontología (concepto, acción o predicado) se define su estructura. Como se observa en el código, cada campo de un esquema debe ser de un tipo predefinido, en este caso se usan los tipos primitivos STRING y INTEGER.

Por cada elemento de la ontología, tenemos que crear una clase Java asociada. Por ejemplo, el concepto Fruta daría lugar a la siguiente clase, que hereda de Concept:

package examples.frutasOntology;
 
import jade.content.Concept;
 
public class Fruta implements Concept {
 
   private String nombre;
   private int precio;
 
   public String getNombre() {
     return nombre;
   }
 
   public void setNombre(String n) {
     nombre = n;
   }
 
   public int getPrecio() {
     return precio;
   }
 
   public void setPrecio(int p) {
     precio = p;
   }
}
 

La clase Oferta, que implementa el predicado “Oferta”, hereda de Predicate:

package examples.frutasOntology;
 
import jade.content.Predicate;
 
public class Oferta implements Predicate {
 
   private Fruta fruta;
 
   public Fruta getFruta() {
     return fruta;
   }
 
   public void setFruta(Fruta f) {
     fruta = f;
   }
}
 

La clase Comprar, que implementa la acción “Comprar” y que, por tanto, hereda de AgentAction:

package examples.frutasOntology;
 
import jade.content.AgentAction;
 
public class Comprar implements AgentAction {
 
   private Fruta fruta;
 
   public Fruta getFruta() {
     return fruta;
   }
 
   public void setFruta(Fruta f) {
     fruta = f;
   }
}
 


Imaginemos dos agentes que comparten esta ontología (Comprador y Vendedor), y que se intercambian mensajes de ofertas. Si Vendedor desea comunicar una oferta de pimientos rojos a 1 euros el kilo, esa información se guarda como un objeto de la clase Oferta, que tenemos que convertir a formato ACL para realizar el acto comunicativo. En el receptor se realizará el proceso contrario, a saber: se recibe un mensaje en formato ACL y se almacena internamente como un objeto de la clase Oferta.

La conversión y las operaciones de chequeo son llevadas a cabo por un objeto que gestiona el contenido, este objeto se denomina ContentManager y está incluído en el paquete jade.content. Cada agente en jade posee un ContentManager al que puede acceder usando el método getContentManager(). Esta clase proporciona todo los métodos de transformación de un objeto a un string para introducirlo en un slot de un ACLMessage y viceversa.

La conversión la realiza a partir de:
  • Una ontología (la que hemos definido).
  • Un codec de un lenguaje de contenido (instancia de la clase Codec del paquete jade.content.lang).

La ontología permite validar la información desde un punto de vista semántico y el codec realiza la conversión a string según las reglas sintácticas del lenguaje de contenido.

JADE define dos lenguajes de contenidos predefinidos. En el paquete jade.content se incluyen dos codecs para dos lenguajes de contenido, los tipos de lenguaje son los siguientes:


Sabiendo todo esto, el último paso consiste en registrar el lenguaje de contenido y la ontología en el método setup() de los agentes.
Primero el agente Comprador:
package examples.frutasOntology;
 
import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.*;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPANames;
import jade.domain.DFService;
import jade.domain.FIPAException;
 
import jade.content.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.content.onto.*;
 
public class Comprador extends Agent {
 
    private Codec codec = new SLCodec();
    private Ontology ontologia = frutasOntology.getInstance();
 
    // Clase que describe el comportamiento que permite recibir un mensaje
    // y contestarlo
    class WaitPingAndReplyBehaviour extends SimpleBehaviour {
      private boolean finished = false;
 
      public WaitPingAndReplyBehaviour(Agent a) {
        super(a);
      }
 
      public void action() {
 
    System.out.println("\nEsperando oferta del Vendedor....");
 
    MessageTemplate mt = MessageTemplate.and(
            MessageTemplate.MatchLanguage(codec.getName()),
            MessageTemplate.MatchOntology(ontologia.getName()));
        ACLMessage  msg = blockingReceive(mt);
 
        try {
 
        if(msg != null){
        if(msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD){
                System.out.println("Mensaje NOT UNDERSTOOD recibido");
            }
        else{
            if(msg.getPerformative()== ACLMessage.INFORM){
 
            ContentElement ce = getContentManager().extractContent(msg);
            if (ce instanceof Oferta){
                // Recibido un INFORM con contenido correcto
                Oferta of = (Oferta) ce;
                Fruta fru = of.getFruta();
                System.out.println("Mensaje recibido:");
                System.out.println("Nombre: " + fru.getNombre());
                System.out.println("Precio: " + fru.getPrecio());
 
                //Compramos
                Comprar compra = new Comprar();
                compra.setFruta(fru);
                ACLMessage msg2 = new ACLMessage(ACLMessage.REQUEST);
                msg2.setLanguage(codec.getName());
                msg2.setOntology(ontologia.getName());
                msg2.setSender(getAID());
                msg2.addReceiver(msg.getSender());
                getContentManager().fillContent(msg2,compra);
                send(msg2);
                System.out.println("Compra solicitada.");
            }
            else{
                // Recibido un INFORM con contenido incorrecto
                ACLMessage reply = msg.createReply();
                reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
                reply.setContent("( UnexpectedContent (expected ping))");
                send(reply);
            }
            }
            else {
                // Recibida una performativa incorrecta
                ACLMessage reply = msg.createReply();
                reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
                reply.setContent("( (Unexpected-act "+ACLMessage.getPerformative(msg.getPerformative())+")( expected (inform)))");
                send(reply);
            }
        }
        }else{
        //System.out.println("No message received");
        }
 
         }
         catch (jade.content.lang.Codec.CodecException ce) {
               System.out.println(ce);
        }
        catch (jade.content.onto.OntologyException oe) {
            System.out.println(oe);
        }
     }
 
      public boolean done() {
        return finished;
      }
 
  } //Fin de la clase WaitPingAndReplyBehaviour
 
  protected void setup() {
 
    getContentManager().registerLanguage(codec);
    getContentManager().registerOntology(ontologia);
    WaitPingAndReplyBehaviour PingBehaviour;
    PingBehaviour = new  WaitPingAndReplyBehaviour(this);
    addBehaviour(PingBehaviour);
 }
}
 

En este caso, el lenguaje elegido es el SL.

Y, por último, el agente Vendedor:
package examples.frutasOntology;
 
import java.io.StringReader;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.PrintWriter;
 
 
import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.*;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.DFService;
import jade.domain.FIPAException;
 
import jade.content.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.content.onto.*;
 
 
public class Vendedor extends Agent {
 
    private Codec codec = new SLCodec();
    private Ontology ontologia = frutasOntology.getInstance();
 
 
    class EnviarMensajeBehaviour extends SimpleBehaviour {
 
      private boolean finished = false;
 
    public EnviarMensajeBehaviour(Agent a) {
        super(a);
    }
 
    public void action() {
        try
    {
            System.out.println("\nIntroduce el nombre del DESTINATARIO (el nombre dado al Agente al lanzar el -container): ");
            BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
            String respuesta = buff.readLine();
            AID r = new AID();
            r.setLocalName(respuesta);
            ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
            msg.setSender(getAID());
            msg.addReceiver(r);
            msg.setLanguage(codec.getName());
               msg.setOntology(ontologia.getName());
 
            System.out.println("\nIntroduce el NOMBRE de la fruta:");
            respuesta = buff.readLine();
            Fruta fru = new Fruta();
            fru.setNombre(respuesta);
            System.out.println("\nIntroduce el PRECIO:");
            respuesta = buff.readLine();
            fru.setPrecio(Integer.parseInt(respuesta));
 
            Oferta of = new Oferta();
            of.setFruta(fru);
 
            getContentManager().fillContent(msg, of);
 
            send(msg);
           }
           catch (java.io.IOException io)
            {System.out.println(io);
        }
        catch (jade.content.lang.Codec.CodecException ce) {
               System.out.println(ce);
        }
        catch (jade.content.onto.OntologyException oe) {
            System.out.println(oe);
        }
    catch (Exception e){
        System.out.println("\n\n... Terminando ...");
        finished=true;
    }
    }
 
    public boolean done() {
 
     return finished;
 
    }
    } // Fin de la clase EnviarMensajeBehaviour
 
    protected void setup() {
 
    /** Registrarse en el DF */
    DFAgentDescription dfd = new DFAgentDescription();
    ServiceDescription sd = new ServiceDescription();
    sd.setType("Vendedor");
    sd.setName(getName());
    sd.setOwnership("ARNOIA");
    dfd.setName(getAID());
    dfd.addServices(sd);
    try {
    DFService.register(this,dfd);
    } catch (FIPAException e) {
        System.err.println(getLocalName()+" registration with DF unsucceeded. Reason: "+e.getMessage());
        doDelete();
    }
 
    getContentManager().registerLanguage(codec);
    getContentManager().registerOntology(ontologia);
 
    EnviarMensajeBehaviour EnviarBehaviour = new EnviarMensajeBehaviour(this);
    addBehaviour(EnviarBehaviour);
    }
 
   protected void takeDown() {
        try {
            DFService.deregister(this);
        }
        catch (FIPAException fe) {
            fe.printStackTrace();
        }
    }
}
 

Después de lanzar la plataforma JADE (java jade.Boot -gui), lanzaremos el agente Comprador:

java jade.Boot -container comprador1:examples.frutasOntology.Comprador
Después ejecutaremos el agente Vendedor:

java jade.Boot -container vendedor1:examples.frutasOntology.Vendedor

Ejercicios

* FIN PARTE 1 *



4.3 Desarrollo de Clases de una Ontología


Cuando trabajamos con ontologías grandes, el trabajo de crear las clases en Java puede llevar mucho tiempo. Protégé es un editor de ontologías open source de libre distribución. Como eclipse, Protégé es una herramienta que puede trabajar con muchos plugins. Gracias a un plugin llamado Beangenerator implementado por C.J. van Aart del departamento (SWI) de la Universidad de Amsterdam, es posible definir ontologías usando Protégé y dejando a BeanGenerator el trabajo de crear el código fuente.

Esto nos permite trabajar con una interfaz gráfica a la hora de definir nuestras ontologías en vez de tener que escribir el código fuente para las clases.

Podemos descargar Protégé de forma gratuita desde la dirección http://protege.stanford.edu/. Nos descargaremos la versión 3.4.4 y procederemos a la instalación, para la cual solo es necesario que tengamos una máquina virtual de Java instalada en nuestro sistema versión 1.5 o superior, de lo contrario deberemos bajarnos el instalable que la incluye.


instalandoProtege.png
Instalando Protégé





Ahora tendremos que instalar el plugin BeanGenerator, que nos permitirá generar las clases de la ontología para trabajar con Jade.
Desde la dirección http://protege.cim3.net/cgi-bin/wiki.pl?OntologyBeanGenerator podremos descargar la versión 3.2.1 de este plugin.

Para instalarlo solo tendremos que descomprimir el archivo beangenerator_bin_Protege_3.2.1.zip en el directorio plugins que cuelga del directorio donde hemos instalado Protégé.


descomprimirBeanGenerator.png
Descomprimiendo el BeanGenerator






También nos bajaremos el fichero de ejemplos beangenerator_examples.zip y lo descomprimiremos en el directorio donde hayamos instalado Protégé.


descomprimirEjemplos.png
Descomprimiendo los ejemplos de BeanGenerator





Ahora ya podemos crear nuestras ontologías con Protégé. Veremos como podríamos implementar la ontología PoliciaOntology para JADE, usando este programa.
OntologiaSara.JPG
Gráfico de la ontología "Policia


Lo primero será iniciar Protégé y desde la pestaña Open other abriremos el proyecto SimpleJADEAbstractOntology.pprj que cuelga de la carpeta examples\ descomprimida anteriormente. Otra opción (aunque no se recomienda)es abrir el mismo proyecto que cuelga del directorio <carpeta_instalacion_protege>\plugins\<plugin_beangenerator>\examples\.
Evidentemente, todo esto también se podrá hacer desde la pestaña File dentro del propio programa.


SMA_1.jpgexternal image moz-screenshot-1.pngexternal image moz-screenshot-2.png





A partir de ahora podremos:
  • Crear conceptos como subclases de la clase Concept.
  • Crear acciones como subclases de la clase AgentAction.
  • Crear agentes como subclases de la clase AID .
  • Crear predicados como subclases de la clase Predicate.


SMA_2.jpg








Para crear un concepto solo tenemos que hacer click con el botón derecho sobre la clase Concept y pulsar Create Class, luego daremos un nombre al concepto. Es importante crear los conceptos antes que los predicados o las acciones, ya que estos últimos van a requerir algún concepto para su definición. Además, hay que fijarse también si existen conceptos que utilicen a otro concepto como tipo de atributo, como veremos a continuación.


SMA_3.jpg






Si nos fijamos en el gráfico, vemos que el primer concepto a crear debe ser Descripcion pues luego será utilizado en el concepto Ladrón.
En este caso daremos el nombre Descripcion al concepto y como este tiene un atributo llamado descripcion, tendremos que crearlo haciendo clic sobre el icono Crear Slot. Desde la ventana de creación de slot seleccionaremos el tipo del atributo, en este caso es una instancia del concepto Descripcion.

Podremos crear slots de tipos básicos como integer, string…etc pero también de clases que hayamos definido previamente, seleccionando como tipo de atributo Class. Después, en el cuadro denomidado Allowed Superclass, hay que pinchar el "círculo amarillo" y seleccionar la clase deseada.
Al crear un slot, sea del tipo que sea, podremos definir su cardinalidad, si es obligatorio u opcional e incluso sus valores por defecto.

Cuando lo hayamos definido cerramos la ventana y automáticamente se guardará.


SMA_4.jpg






Para crear un predicado seguiremos los mismos pasos, seleccionaremos Create Class desde el menú desplegable y daremos un nuevo nombre al predicado.


SMA_5.jpg







A la hora de asignar nombre tanto a clases como a slots, tendremos que tener cuidado de no elegir nombres que ya estén asignados. Si es así, se mostrarán en color rojo y no nos permitirá crear la clase o el slot.


10.nombre_repetido.JPG
Lo que sucede si el nombre ya está en uso






Si el atributo de una clase tiene como tipo otra clase, como pasa en el caso del predicado LadronDetenido, solo tendremos que seleccionar Class en Value Type, pulsar el icono Add Class y seleccionar la clase correcta.


8.seleccionando_clase_existente.JPG
Seleccionando una clase existente como tipo de atributo





Después de definir todos los conceptos y los predicados, vamos a definir las acciones, en este caso definiremos la acción DetenerLadron, lo haremos de forma análoga a como hemos creado los conceptos y los predicados. Para ello, pinchamos en AgentAction, que cuelga de Concept.


7.creando_accion.JPG
Creando una nueva accion





Si tenemos que añadir algún atributo que ya se ha definido previamente, como es el caso del atributo LADRON, que ya ha sido usado en el predicado LadronDetenido, pulsaremos el icono Add slot y desde ahí seleccionaremos el atributo correcto, en este caso LADRON.


9.en_accion_seleccionando_slot_ya_creado.JPG
Seleccionando un slot ya creado





Ahora que ya hemos definido la ontología, vamos a usar BeanGenerator para que nos genere el código fuente en Java para JADE.
Primero activemos el plugin. Desde el menú Project seleccionamos la opción Configure… y marcamos la opción OntologyBeanGeneratorTab y pulsamos OK.

protege10.png



Ahora desde la pestaña Ontology Bean Generator elegimos el nombre del paquete en que se va a englobar la ontología, luego el directorio donde queremos que nos genere el código y por ultimo el nombre que queremos para nuestra ontología.


protege11.png



Al pulsar el botón Generate Beans el plugin nos creará todos los ficheros de las clases que componen la ontología.


Como se puede observar, BeanGenerator hace el trabajo más tedioso a la hora de definir la ontología por nosotros:

// file: PoliciaOntology.java generated by ontology bean generator.  DO NOT EDIT, UNLESS YOU ARE REALLY SURE WHAT YOU ARE DOING!
package policiaOntology;
 
import jade.content.onto.*;
import jade.content.schema.*;
import jade.util.leap.HashMap;
import jade.content.lang.Codec;
import jade.core.CaseInsensitiveString;
 
/** file: PoliciaOntology.java
 * @author ontology bean generator
 * @version 2010/05/6, 17:12:47
 */
public class PoliciaOntology extends jade.content.onto.Ontology  {
  //NAME
  public static final String ONTOLOGY_NAME = "policia";
  // The singleton instance of this ontology
  private static ReflectiveIntrospector introspect = new ReflectiveIntrospector();
  private static Ontology theInstance = new PoliciaOntology();
  public static Ontology getInstance() {
     return theInstance;
  }
 
 
   // VOCABULARY
    public static final String DISPONIBLE_TIEMPO="TIEMPO";
    public static final String DISPONIBLE="Disponible";
    public static final String NODISPONIBLE_MOTIVO="MOTIVO";
    public static final String NODISPONIBLE="NoDisponible";
    public static final String LADRONDETENIDO_LADRON="ladron";
    public static final String LADRONDETENIDO="LadronDetenido";
    public static final String DETENERLADRON_LADRON="ladron";
    public static final String DETENERLADRON="DetenerLadron";
    public static final String TIEMPOLLEGADA_TIEMPO="tiempo";
    public static final String TIEMPOLLEGADA="TiempoLlegada";
    public static final String DESCRIPCION_COLORPELO="colorPelo";
    public static final String DESCRIPCION_PESO="peso";
    public static final String DESCRIPCION_ALTURA="altura";
    public static final String DESCRIPCION="Descripcion";
    public static final String MOTIVO_MOTIVO="motivo";
    public static final String MOTIVO="Motivo";
    public static final String LADRON_DESCRIPCION="descripcion";
    public static final String LADRON="Ladron";
 
  /**
   * Constructor
  */
  private PoliciaOntology(){
    super(ONTOLOGY_NAME, BasicOntology.getInstance());
    try {
 
    // adding Concept(s)
    ConceptSchema ladronSchema = new ConceptSchema(LADRON);
    add(ladronSchema, policiaOntology.Ladron.class);
    ConceptSchema motivoSchema = new ConceptSchema(MOTIVO);
    add(motivoSchema, policiaOntology.Motivo.class);
    ConceptSchema descripcionSchema = new ConceptSchema(DESCRIPCION);
    add(descripcionSchema, policiaOntology.Descripcion.class);
    ConceptSchema tiempoLlegadaSchema = new ConceptSchema(TIEMPOLLEGADA);
    add(tiempoLlegadaSchema, policiaOntology.TiempoLlegada.class);
 
    // adding AgentAction(s)
    AgentActionSchema detenerLadronSchema = new AgentActionSchema(DETENERLADRON);
    add(detenerLadronSchema, policiaOntology.DetenerLadron.class);
 
    // adding AID(s)
 
    // adding Predicate(s)
    PredicateSchema ladronDetenidoSchema = new PredicateSchema(LADRONDETENIDO);
    add(ladronDetenidoSchema, policiaOntology.LadronDetenido.class);
    PredicateSchema noDisponibleSchema = new PredicateSchema(NODISPONIBLE);
    add(noDisponibleSchema, policiaOntology.NoDisponible.class);
    PredicateSchema disponibleSchema = new PredicateSchema(DISPONIBLE);
    add(disponibleSchema, policiaOntology.Disponible.class);
 
 
    // adding fields
    ladronSchema.add(LADRON_DESCRIPCION, descripcionSchema, ObjectSchema.OPTIONAL);
    motivoSchema.add(MOTIVO_MOTIVO, (TermSchema)getSchema(BasicOntology.STRING), ObjectSchema.OPTIONAL);
    descripcionSchema.add(DESCRIPCION_ALTURA, (TermSchema)getSchema(BasicOntology.INTEGER), ObjectSchema.OPTIONAL);
    descripcionSchema.add(DESCRIPCION_PESO, (TermSchema)getSchema(BasicOntology.INTEGER), ObjectSchema.OPTIONAL);
    descripcionSchema.add(DESCRIPCION_COLORPELO, (TermSchema)getSchema(BasicOntology.STRING), ObjectSchema.OPTIONAL);
    tiempoLlegadaSchema.add(TIEMPOLLEGADA_TIEMPO, (TermSchema)getSchema(BasicOntology.INTEGER), ObjectSchema.OPTIONAL);
    detenerLadronSchema.add(DETENERLADRON_LADRON, ladronSchema, ObjectSchema.OPTIONAL);
    ladronDetenidoSchema.add(LADRONDETENIDO_LADRON, ladronSchema, ObjectSchema.OPTIONAL);
    noDisponibleSchema.add(NODISPONIBLE_MOTIVO, motivoSchema, ObjectSchema.OPTIONAL);
    disponibleSchema.add(DISPONIBLE_TIEMPO, tiempoLlegadaSchema, ObjectSchema.OPTIONAL);
 
    // adding name mappings
 
    // adding inheritance
 
   }catch (java.lang.Exception e) {e.printStackTrace();}
  }
  }
 


4.3.1 Desarrollo de clases de una ontología


Ahora que ya sabemos qué es, para qué sirve y cómo se utiliza una ontología, aprenderemos cómo crear nuestras propias ontologías.

Para desarrollar y utilizar una ontología se deben realizar cinco pasos:
  1. Definir una ontología incluyendo los schemas para los tipos de predicados, acciones de agentes y conceptos del dominio de la aplicación.
  2. Desarrollar las clases JAVA apropiadas para cada uno de los elementos de la ontología.
  3. Seleccionar un lenguaje de contenido adecuado entre los que proporciona JADE.
  4. Registrar la ontología y el lenguaje de contenido en el agente.
  5. Crear y manejar expresiones de contenido como objetos Java y dejar que JADE haga la traducción en/desde String.

Para desarrollar nuestra ontología podemos hacerlo codificando a mano las clases, tal y como se hizo en la presentación anterior; o bien haciendo uso de la herramienta visual Protégé, como en el apartado anterior.

OntologiaSara.JPG


La ontología PoliciaOntology consta de tres conceptos:
  • Ladron, que contiene un atributo de tipo Descripcion que guarda la descripción del Ladrón.
  • Motivo, que contiene un atributo de tipo String donde se especifica el motivo (usado en los predicados).
  • Descripcion, que contiene los atributos Altura, ColorPelo y Peso que componen la descripción del Ladrón.
  • TiempoLlegada, que contiene un atributo de tipo Integer que representa el tiempo en minutos.

De tres predicados:
  • LadronDetenido, que indica que el Ladrón ha sido detenido.
  • NoDisponible, indica el hecho de no estar disponible y contiene el concepto Motivo donde se indica el motivo por el cual no se puede coger al ladrón.
  • Disponible, que indica el hecho de haber recibido la petición de captura y el tiempo que se tardará en llegar al lugar del suceso.

Finalmente, nuestra ontologia contiene una acción:
  • DetenerLadrón, que solicita al agente que vaya a detener al Ladrón.

Ahora, para cada uno de los elementos de la ontología se crearían las clases java apropiadas a mano, que tienen que implementar las interfaces jade.content.Concept, jade.content.Predicate y jade.content.AgentAction dependiendo de si se trata de un concepto, un predicado o una acción respectivamente; o bien se utilizaría Protégé para evitar todo ese trabajo.

Una vez creada la ontología, es el momento de generar los agentes que la utilicen. En nuestro ejemplo son las clases Testigo y Comisaria.

Antes de mostrar el código de estas clases, se presenta un esquema representativo de la comunicación entre los agentes que interactuarán en este sistema:

EsquemaSara.JPG

Testigo.java

import jade.core.Agent;
import jade.core.AID;
import jade.lang.acl.*;
import jade.proto.AchieveREInitiator;
import jade.domain.FIPANames;
 
import policiaOntology.*;
 
import jade.content.*;
import jade.content.lang.*;
import jade.content.lang.sl.*;
import jade.content.onto.*;
import jade.content.onto.basic.*;
import java.io.*;
 
 
public class Testigo extends Agent {
 
   private Codec codec = new SLCodec();
   private Ontology ontologia = PoliciaOntology.getInstance();
 
   protected void setup(){
 
    try{
 
        Object[] args = getArguments();
        if (args != null && args.length > 0) {
 
            System.out.println("Acaban de robar, solicitando ayuda a la comisaria de policia...");
            ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
 
            for(int i=0; i<args.length ; i++)
                msg.addReceiver(new AID((String) args[i], AID.ISLOCALNAME));
 
            // Se establece el protocolo de comunicaciones
            msg.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST);
 
            // Se establece el lenguaje de contenido y la ontología del mensaje.
            msg.setLanguage(codec.getName());
            msg.setOntology(ontologia.getName());
 
            // Obtener los detalles del ladron a buscar
            try{
                BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
                Ladron l = new Ladron();
                Descripcion d = new Descripcion();
 
                System.out.println("");
                System.out.println("-----------------------------------------------------");
                System.out.println("    INTRODUCE los detalles del ladron a buscar:");
                System.out.print("      Color de pelo --> ");
                d.setColorPelo(buff.readLine());
                System.out.print("      Altura aproximada (cm) ---> ");
                d.setAltura(new Integer(buff.readLine()));
                System.out.print("      Peso aproximado -----> ");
                d.setPeso(new Integer(buff.readLine()));
                l.setDescripcion(d);
 
                System.out.println("");
                System.out.println("-----------------------------------------------------");
                System.out.println("");
 
 
                // Crea la accion DetenerLadron
                 DetenerLadron dl = new DetenerLadron();
                dl.setLadron(l);
 
 
                // Registra el lenguaje de contenido y la ontologia utilizada
                getContentManager().registerLanguage(codec);
                getContentManager().registerOntology(ontologia);
 
 
                // Crea la accion a enviar asociándola a la acción DetenerLadron creada
                Action a = new Action(getAID(), dl);
 
 
                // Rellena el mensaje ACL para que sea consistente con el lenguaje de contenido y la ontologia
                getContentManager().fillContent(msg,a);
 
                addBehaviour(new ManejadorInitiator(this,msg));
            }
            catch (IOException ioe) {
                System.err.println("Error I/O: " + ioe.getMessage());
            }
 
        }else System.out.println("Especifique el nombre de al menos algun agente comisaria.");
 
    } catch (jade.content.lang.Codec.CodecException ce) {  System.out.println(ce);
 
    } catch (jade.content.onto.OntologyException oe) {  System.out.println(oe);  }
   }
 
 
 
 
   class ManejadorInitiator extends AchieveREInitiator{
 
    public ManejadorInitiator(Agent a,ACLMessage msg)
    {  super(a,msg);  }
 
 
    protected void handleAgree(ACLMessage agree)
    {
        try{
                // Decodifica el mensaje ACL recibido mediante el lenguaje de contenido y la ontologia actuales
                ContentElement ce = getContentManager().extractContent(agree);
 
                if (ce instanceof Disponible)
            {
                // Recibido un AGREE con contenido correcto
                Disponible disp = (Disponible) ce;   // Transforma el contenido en el objeto predicado EstoyDisponible de la ontologia
 
                System.out.println("La comisaria " + agree.getSender().getName() + " informa que va a encontrar al ladron. Tardara en llegar " + disp.getTIEMPO().getTiempo() +" min");
                }
                else
                System.out.println("Recibido mensaje de tipo AGREE desde comisaria "+agree.getSender().getName()+" cuyo contenido no es el esperado.");
 
        } catch (Exception ce) {  System.out.println(ce);  }
    }
 
 
    protected void handleInform(ACLMessage inform)
    {
        try{
 
                // Decodifica el mensaje ACL recibido mediante el lenguaje de contenido y la ontologia actuales
                ContentElement ce = getContentManager().extractContent(inform);
 
                if (ce instanceof LadronDetenido)
                {
                    // Recibido un INFORM con contenido correcto
                    LadronDetenido ld = (LadronDetenido) ce; // Transforma el contenido en el objeto predicado LadronDetenido de la ontologia
 
                    System.out.println("La comisaria " + inform.getSender().getName() + " informa que ha detenido al ladron!!");
                }
                else
                    System.out.println("Recibido mensaje de tipo INFORM desde la comisaria "+inform.getSender().getName()+" cuyo contenido no es el esperado.");
 
        } catch (Exception ce) {  System.out.println(ce);  }
    }
 
 
    protected void handleRefuse(ACLMessage refuse)
    {
        try{
 
                // Decodifica el mensaje ACL recibido mediante el lenguaje de contenido y la ontologia actuales
                ContentElement ce = getContentManager().extractContent(refuse);
                if (ce instanceof NoDisponible)
                {
                    // Recibido un REFUSE con contenido correcto
                    NoDisponible nd = (NoDisponible) ce; // Transforma el contenido en el objeto predicado NoDisponible de la ontologia
 
                    System.out.println("La comisaria " + refuse.getSender().getName() + " informa que NO puede detener al ladron. Motivo: " + nd.getMOTIVO().getMotivo());
                }
                else
                    System.out.println("Recibido mensaje de tipo REFUSE desde comisaria "+refuse.getSender().getName()+" cuyo contenido no es el esperado.");
 
        } catch (Exception ce) {  ce.printStackTrace();  }
    }
 
 
 
    protected void handleNotUnderstood(ACLMessage notUnderstood)
    {
        System.out.println("La comisaria " + notUnderstood.getSender().getName()  + " no entiende el mensaje.");
    }
 
 
   }
}


Comisaria.java

import policiaOntology.*;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.*;
import jade.content.onto.basic.*;
import jade.core.Agent;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.proto.AchieveREResponder;
import jade.domain.FIPANames;
import jade.domain.FIPAAgentManagement.NotUnderstoodException;
import jade.domain.FIPAAgentManagement.RefuseException;
import jade.domain.FIPAAgentManagement.FailureException;
 
 
 
 
public class Comisaria extends Agent {
 
   private Codec codec = new SLCodec();
   private Ontology ontologia = PoliciaOntology.getInstance();
   private double DISTANCIA_MAX;
   private double DISTANCIA_ROBO;
 
 
   protected void setup()
   {
    DISTANCIA_MAX=(Math.random()*10);
    DISTANCIA_ROBO=(Math.random()*10);
        System.out.println("[Comisaria "+getLocalName()+"] : Pendiente de avisos...");
 
    // Crea una plantilla que solo acepte los mensajes ACL recibidos que utilizan el protocolo FIPA_REQUEST
        // Y ademas que sean del tipo REQUEST
        // Y ademas que esten codificados mediante el lenguaje de contenido SLCodec
        // Y que utilicen la ontologia policiaOntology
        MessageTemplate protocolo = MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST);
        MessageTemplate performativa = MessageTemplate.MatchPerformative(ACLMessage.REQUEST);
        MessageTemplate lenguajeContenido = MessageTemplate.MatchLanguage(codec.getName());
        MessageTemplate ontoTemplate = MessageTemplate.MatchOntology(ontologia.getName());
 
        MessageTemplate plantilla = MessageTemplate.and(MessageTemplate.and(protocolo, performativa),MessageTemplate.and(lenguajeContenido, ontoTemplate));
 
        // Registra el lenguaje de contenido y la ontologia en el gestor de contenidos
        getContentManager().registerLanguage(codec);
        getContentManager().registerOntology(ontologia);
 
        addBehaviour(new ManejadorResponder(this, plantilla));
   }
 
 
   class ManejadorResponder extends AchieveREResponder
   {
 
      public ManejadorResponder(Agent a,MessageTemplate mt)
      {
          super(a,mt);
      }
 
 
      protected ACLMessage prepareResponse(ACLMessage request)
      {
 
        ACLMessage respuesta = request.createReply();
            try
            {
                // Decodifica el mensaje ACL recibido a un objeto de tipo Action mediante el lenguaje de contenido y la ontologia actuales
                Action a = (Action) myAgent.getContentManager().extractContent(request);
                // Recupera el objeto accion de la ontologia
                DetenerLadron dl = (DetenerLadron) a.getAction();
 
        // Recibido un INFORM con contenido correcto
 
                String colorPelo=dl.getLadron().getDescripcion().getColorPelo();
                float altura=dl.getLadron().getDescripcion().getAltura();
                int peso=dl.getLadron().getDescripcion().getPeso();
 
        System.out.println("[Comisaria "+getLocalName()+"] : Hemos recibido una llamada de " + request.getSender().getName() + " avisando de un robo.");
        System.out.println("[Comisaria "+getLocalName()+"] : Intentando localizar su ubicacion...");
 
 
                if (DISTANCIA_ROBO <= DISTANCIA_MAX)
                {
                      System.out.println("[Comisaria "+getLocalName()+"] : Salimos a todo meter en busca de un hombre que responde a la siguiente descripcion:");
                      System.out.println("----------------------------------------");
                      System.out.println("  Color de pelo:      "+colorPelo);
                      System.out.println("  Altura aproximada:  "+altura/100+" m");
                      System.out.println("  Peso aproximado:    "+peso+" kg");
                      System.out.println("----------------------------------------");
                      System.out.println("");
 
                      respuesta.setPerformative(ACLMessage.AGREE);
 
                      // Crea un predicado Disponible de la ontologia añadiandole el concepto TiempoLlegada
                      TiempoLlegada tl = new TiempoLlegada();
                      tl.setTiempo((int)(Math.random()*10));
                      Disponible disp = new Disponible();
                      disp.setTIEMPO(tl);
 
                      getContentManager().fillContent(respuesta,disp);
              }
              else
              {
                        System.out.println("[Comisaria "+getLocalName()+"]: Ubicacion del robo fuera de nuestro ambito de actuacion. Pasamos!!");
                        respuesta.setPerformative(ACLMessage.REFUSE);
 
                        // Crea un predicado NoDisponible de la ontologia y le añade el concepto Motivo
                        Motivo m = new Motivo();
                        m.setMotivo("Robo demasiado lejos.");
                        NoDisponible nd = new NoDisponible();
                        nd.setMOTIVO(m);
 
                        getContentManager().fillContent(respuesta, nd);
               }
 
            }catch (Exception ex)
            {
                ex.printStackTrace();
                System.out.println(getLocalName()+": Error manejando la acción de detener ladron");
                System.out.println(ex.getMessage().toString());
            }
 
            return respuesta;
    }
 
 
 
    protected ACLMessage prepareResultNotification(ACLMessage request,ACLMessage response)
    {
 
        // Si la policia fue a detener al ladron
        ACLMessage inform = request.createReply();
 
        try
            {
                ContentElement ce = getContentManager().extractContent(response);
 
                Disponible disp = (Disponible)ce;
                System.out.println("[Comisaria "+getLocalName()+"]: Hemos conseguido detener al ladron!!");
                inform.setPerformative(ACLMessage.INFORM);
 
                Action a = (Action) myAgent.getContentManager().extractContent(request);
 
                DetenerLadron dl = (DetenerLadron) a.getAction();
                // Crea un predicado LadronDetenido de la ontologia y le añade el ladron detenido
                LadronDetenido ld = new LadronDetenido();
                ld.setLadron(dl.getLadron());
                getContentManager().fillContent(inform,ld);
 
 
             } catch (Exception ex)
             {
                System.out.println(getLocalName()+": Error manejando el predicado Disponible");
                System.out.println(ex.getMessage().toString());
             }
 
             return inform;
        }
 
    }
}
 
 


Ahora ya la podríamos utilizar tal y como se explicó en el principio de este capítulo.
En los siguientes puntos se explicará cómo seleccionar un lenguaje de contenido y cómo registrar la ontología y dicho lenguaje.


4.4 Selección de un lenguaje de contenido


Los paquetes jade.content.lang.sl y jade.content.lang.leap incluyen los codecs para los lenguajes de contenido SL y LEAP. Un códec para un lenguaje de contenido L es un objeto Java capaz de manejar expresiones de contenido escritas en ese mismo lenguaje L. En la mayoría de los casos un desarrollador puede adoptar uno de esos dos lenguajes de contenido y usar el códec relacionado sin ningún esfuerzo a mayores.

Si un desarrollador quisiese que sus agentes se comunicases en un lenguaje distinto podría definir un códec.
El lenguaje SL es un lenguaje codificado en Strings entendible por las personas y probablemente (Junto con KIF) sea el lenguaje de contenido más difundido en la comunidad de científicos que trabajan con agentes inteligentes.

En general es recomendable usar este lenguaje para aplicaciones basadas en agentes que son abiertas (donde los agentes de diferentes desarrolladores y corriendo en diferentes plataformas se deban comunicar).

SL incluye operadores lógicos (AND, OR, NOT) y operadores modales (BELIEF, INTENTION, UNCERTAINTY). Además la propiedad de ser fácilmente entendible por los humanos puede resultar útil a la hora de depurar las aplicaciones.

El lenguaje LEAP por su parte es un lenguaje de contenido no entendible por las personas (una expresión en LEAP es una secuencia de bytes) que fue definido ad hoc por el equipo de JADE dentro del proyecto LEAP. Está por lo tanto claro que sólo los agentes JADE pueden hablar en el lenguaje LEAP.
Hay ciertos casos en los que el lenguaje LEAP es preferible respecto a SL:
  • La clase LEAPCodec es más ligera que la clase SLCodec. Cuando hay fuertes limitaciones de memoria es preferible usar LEAP.
  • A diferencia del lenguaje LEAP, el lenguaje SL no soporta secuencias de bytes.

Finalmente, el desarrollador deberá tener en cuenta que el lenguaje SL trabaja de forma particular con las acciones. Todas las acciones de los agentes en SL deben ser insertadas en el constructor ACTION (incluido en la clase BasicOntology e implementado en la clase jade.content.onto.basic.Action) que asocia la acción del agente al AID del agente que se propuso realizar la acción.
A continuación podemos ver el cacho de código para el ejemplo de la policía donde se selecciona el lenguaje de contenido SL. Se muestra como ejemplo el Testigo, pero el agente Commisaría lo haría de forma análoga.

Testigo.java
...
import jade.content.lang.sl.*;
...
public class Testigo extends Agent {
    private Codec codec = new SLCodec();
    private Ontology ontologia = PoliciaOntology.getInstance();
...
 

4.5 Registro de una ontología y de un lenguaje de contenido


Antes de que un agente pueda usar una ontología y un lenguaje de contenido, estos deben ser registrados en el content manager del agente. Esta operación es típicamente (aunque no necesario) incluirla en el método setup() de la clase Agent. El siguiente código muestra el registro en el caso del agente Testigo (el agente Comisaria lo hace de forma análoga) asumiendo que se va a usar el lenguaje SL.

Testigo.java
public class Testigo extends Agent {
    private Codec codec = new SLCodec();
    private Ontology ontologia = PoliciaOntology.getInstance();
    protected void setup(){
    ...
    // Registra el lenguaje de contenido y la ontologia utilizada
    getContentManager().registerLanguage(codec);
    getContentManager().registerOntology(ontologia);
    ...
    }
...
 

Desde ahora el content manager asociará los objetos Codec y Ontology a los String devueltos por sus respectivos métodos getName().
Hay que tener en cuenta que es una buena práctica tener un objeto singleton para la ontología, este no es el caso del objeto del códec, ya que se pueden dar problemas de sincronización durante las operaciones de parseo.

Ahora podemos probar ya nuestra ontología. Descárgate el siguiente fichero.zip, compila tanto los agentes Testigo.java y Comisaria.java como los fuentes JAVA de la ontología PoliciaOntology y ejecuta los agentes en el siguiente orden:
  • Primero lanza el gui de JADE: java jade.Boot -gui.
  • Luego lanza uno o varios agentes Comisaria: java jade.Boot -container AsLagoas:Comisaria APonte:Comisaria OCouto:Comisaria Barrocas:Comisaria
  • Finalmente lanza el agente Testigo pasándole como parámetros las comisarias: java jade.Boot -container PedroCuesta:Testigo(AsLagoas,APonte,OCouto,Barrocas)



SMA_6.jpg


SMA_7.jpg






4.6 Ejercicios


PRIMERA PARTE


Normas de entrega:


Enviar el código del ejercicio a: viticlick@gmail.com
En el email incluir:
  • Nombre y Apellido
  • Grupo
  • Respuesta código modificado (.zip)

Ejercicio: librosOntology


Material de apoyo:


En el siguiente ejemplo, completar el código de los archivos incluidos para que funcione:

  • Supongamos una Ontología para un profesor que asigna seminarios, un alumno recibe el trabajo de un profesor.
  • La ontología seminariosOntology consta de un Concept (Seminario) definido por un Tema y los Puntos que vale.
  • El agente Profesor le envia al agente Alumno un predicado Trabajo para hacerle saber que puede Realizar el Seminario indicado.
  • Para la ejecución, es necesario que exista un alumno.
SeminarioOntologyEsquema.jpg


SEGUNDA PARTE



Normas de entrega:


Enviar comprimida la carpeta Universidad, cuyo contenido se especificará a continuación, a la siguiente dirección: jtabadin@esei.uvigo.es.

En el email incluir:
  • Nombre y Apellidos
  • Grupo ()
  • Ficheros java generados por Protégé.
  • Ficheros java de los agentes.

Ejercicio 3: Desarrollar una ontología con Protégé


El ejercicio que se presenta a continuación trata de recrear un sistema para gestionar la admisión a una universidad.
Para ello se debe desarrollar una ontología con la siguiente estructura:

Captura.PNG

Como se puede apreciar, consta de los siguientes elementos:

Conceptos

  • Persona: hace referencia a la persona que desea matricularse en la universidad.
  • Motivo: especifica el motivo por el cual no se ha admitido una persona.

Predicados

  • Admitida: sirve para hacer referencia a la situación en que una persona se encuentra admitida o no.
  • NoSuperaNota: sirve para hacer referencia a la situación de que una persona no puede matricularse por no superar la nota de corte.
  • ErrorAdmision: sirve para hacer referencia a la situación en que una persona no ha sido admitida por un motivo concreto.

Acciones

  • Admitir: representa a la acción de registrar a una persona en la universidad.
  • Excluir: representa a la acción de eliminar a una persona de la universidad.

La ontología Universidad será utilizada por dos agentes, que son instancias de las clases siguientes:
  • SecretarioAgent: representa a la persona encargada de matricular o borrar personas de la universidad.
  • UniversidadAgent: representa a la universidad, encargado de contabilizar las personas que se van anotando o desvinculando de la misma, y de impedir el registro de más personas una vez se haya alcanzado el limite de plazas.


SecretarioAgent.java
import jade.lang.acl.ACLMessage;
 
import jade.core.*;
import jade.core.behaviours.*;
 
import jade.domain.FIPAException;
import jade.domain.FIPANames;
 
import jade.proto.SimpleAchieveREInitiator;
 
import jade.content.lang.Codec;
import jade.content.lang.sl.*;
 
import jade.domain.*;
import jade.content.*;
import jade.content.abs.*;
import jade.content.onto.*;
import jade.content.onto.basic.*;
 
import universidadOntology.*;
 
import java.util.Vector;
import jade.util.leap.*;
import java.io.*;
 
 
public class SecretarioAgent extends Agent {
 
    public static int seleccion=0;
 
    // COMPORTAMIENTOS DEL AGENTE
    /**
        Comportamiento principal del RequesterAgent
        Primero se pide al usuario la accion que desea llevar a cabo [admitir|excluir]
        [Admitir]    se pide al usuario los detalles de la persona
                   se comprueba que la persona indicada no pertenece a la universidad
                               de acuerdo con la comprobacion anterior se solicita la admison
        [Excluir] se pide al usuario el dni de la persona
                   se comprueba que la persona indicada pertenece a la universidad
                   de acuerdo con la comprobación anterior se solicita la exclusion
        Este comportamiento se ejecuta ciclicamente
    */
    class HandleAdmisionExclusionBehaviour extends SequentialBehaviour {
        // Variables locales
        Behaviour queryBehaviour = null;
        Behaviour requestBehaviour = null;
 
        // Constructor
        public HandleAdmisionExclusionBehaviour(Agent myAgent){
            super(myAgent);
        }
 
        // Esto es ejecutado al principio del comportamiento
        public void onStart(){
            // Obtener los detalles de la persona a incluir en la universidad
            try
            {
                BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
                String opcion = "";
                String dni = "";
                String nota = "";
                int notaMedia;
                do
                {
                    System.out.println("  \n\nBIENVENIDO, soy el encargado de gestionar la reserva de plazas para la universidad\n");
                    System.out.println("  Puedes escoger entre las siguientes opciones:");
                    System.out.println("  --> 1. Admitir a una persona en la universidad ");
                    System.out.println("  --> 2. Excluir a una persona en la universidad ");
                    System.out.println("  Que deseas hacer? [1|2]");
                    opcion = buff.readLine();
                }
                while ( !(opcion.equalsIgnoreCase("1") || opcion.equalsIgnoreCase("2")) );
                Persona p = new Persona();
                if (opcion.equalsIgnoreCase("1"))
                {
                    seleccion = 1;
                    System.out.println("  \nIntroduce los detalles de la persona a registrar\n");
                    System.out.print("  Nombre de la persona --> ");
                    p.setNombre(buff.readLine());
                    System.out.print("  Titulacion --> ");
                    p.setTitulacion(buff.readLine());
        do
        {
                    System.out.print("  Nota media de la persona   --> ");
                nota = buff.readLine();
                notaMedia = Integer.parseInt(nota);
 
        }
        while ( notaMedia > 10 || notaMedia < 0 );
        p.setNota(notaMedia);
                }
                if (opcion.equalsIgnoreCase("2"))
                {
                    seleccion = 2;
                    System.out.println("  \nIntroduce los detalles de la persona a excluir");
                    p.setNombre("");
                    p.setNota(99);
                }
                do
                {
                    System.out.print("  DNI (8 digitos)      --> ");
                    dni = buff.readLine();
                }
                while ( dni.length() != 8);
                p.setDni(dni);
                System.out.print("\n");
 
                //Crear un objeto representando el hecho de que la persona p esta admitida en la universidad, mediante el predicado Works-for
                Admitida adm = new Admitida();
                adm.setPersona(p);  //La persona cuyos datos hemos obtenido por consola
 
 
                Ontology o = myAgent.getContentManager().lookupOntology(UniversidadOntology.ONTOLOGY_NAME);
                //Crear un mensaje ACL para hacer una peticion al UniversidadAgent para que nos diga si el predicado de arriba es verdadero o falso
                //Es decir, intentamos verficar si la persona se encuentra ya registrada en la universidad o no
                ACLMessage queryMsg = new ACLMessage(ACLMessage.QUERY_IF);
                queryMsg.addReceiver(((SecretarioAgent) myAgent).universidad);
                queryMsg.setLanguage(FIPANames.ContentLanguage.FIPA_SL0);
                queryMsg.setOntology(UniversidadOntology.ONTOLOGY_NAME);
                //Escribe el predicado Admitida en el mensaje
 
                    try
                {
                        myAgent.getContentManager().fillContent(queryMsg, adm);
                    }
                catch (Exception e)
                {
                        e.printStackTrace();
                    }
 
                    // Crea y añade un comportamiento para hacer peticiones al UniversidadAgent para saber
                // si una persona p ya esta admitida en la universidad siguiendo el protocolo FIPA-Query
                //Le pasamos como parametro el mensaje con el predicado admitida que queremos chequear
                queryBehaviour = new CheckAlreadyAdmitidaBehaviour(myAgent, queryMsg);
                addSubBehaviour(queryBehaviour);
            }
            catch (IOException ioe) {
                System.err.println("Error I/O: " + ioe.getMessage());
            }
 
        }
 
        //Esto se ejecuta el final del comportamiento
        public int onEnd(){
            //Comprobar si el usuario quiere continuar
            try{
                BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
                String stop = "";
                do
                {
                    System.out.println("  \nQuieres continuar? [s|n] ");
                    stop = buff.readLine();
                    if (stop.equalsIgnoreCase("s"))
                    {
                        reset(); // Esto hace que el comportamiento se ejecute ciclicamente
                        myAgent.addBehaviour(this);
                    }
                    else
                    {
                            myAgent.doDelete(); // Exit
                        System.exit(0);
                    }
                }
                while ( !(stop.equalsIgnoreCase("s") || stop.equalsIgnoreCase("n")) );
            }
            catch (IOException ioe) {
                System.err.println("Error I/O: " + ioe.getMessage());
            }
            return 0;
        }
 
 
 
        //Extiende el metodo reset para poder quitar los sub-comportamientos
        //que son añadidos dinamicamente
        public void reset(){
            if (queryBehaviour != null){
                removeSubBehaviour(queryBehaviour);
                queryBehaviour = null;
            }
            if (requestBehaviour != null){
                removeSubBehaviour(requestBehaviour);
                requestBehaviour = null;
            }
            super.reset();
        }
    }
 
 
    /**
        Este comportamiento encapsula la comprobacion de que la persona indicada esta o no esta
        actualmente admitida en la universidad
        Esto se hace siguiendo el protocolo de interaccion FIPA-Query
    */
    class CheckAlreadyAdmitidaBehaviour extends SimpleAchieveREInitiator {
        // Constructor
        public CheckAlreadyAdmitidaBehaviour(Agent myAgent, ACLMessage queryMsg){
            super(myAgent, queryMsg);
            queryMsg.setProtocol(FIPANames.InteractionProtocol.FIPA_QUERY);
        }
 
        protected void handleInform(ACLMessage msg) {
            try{
                AbsPredicate cs = (AbsPredicate)myAgent.getContentManager().extractAbsContent(msg);
                Ontology o = myAgent.getContentManager().lookupOntology(UniversidadOntology.ONTOLOGY_NAME);
                if (cs.getTypeName().equals(UniversidadOntology.ADMITIDA))
                {
                    if (seleccion == 1)
                    {
                        //La persona indicada ya esta admitida en la universidad
                        // Informar al usuario, ya no vamos a pedir la admision
                        Admitida adm = (Admitida)o.toObject((AbsObject)cs);
                        Persona p = (Persona) adm.getPersona();
                        System.out.println("  /*/ La persona " + p.getNombre() + " ya esta admitida en la universidad.");
                    }
                    if (seleccion == 2)
                    {
                        Predicate pred = (Predicate)myAgent.getContentManager().extractContent(msg);
                        Admitida adm = (Admitida)pred;
                        Persona p = (Persona) adm.getPersona();
                        Excluir ex = new Excluir();
                        ex.setPersona(p);
                        Action a = new Action();
                        a.setActor(((SecretarioAgent) myAgent).universidad);
                        a.setAction(ex);
 
                        ACLMessage requestMsg = new ACLMessage(ACLMessage.REQUEST);
                        requestMsg.addReceiver(((SecretarioAgent) myAgent).universidad);
                        requestMsg.setLanguage(FIPANames.ContentLanguage.FIPA_SL0);
                        requestMsg.setOntology(UniversidadOntology.ONTOLOGY_NAME);
                            // Escribir la accion en el mensaje
 
                            try
                        {
                                myAgent.getContentManager().fillContent(requestMsg, a);
                        }
                        catch (Exception pe) {}
                        //Crear y añadir un comportamiento para pedirle al UniversidadAgent la admision
                        //de la persona p siguiendo el protocolo FIPA-Request
                        ((HandleAdmisionExclusionBehaviour) parent).requestBehaviour = new RequestAdmisionExclusionBehaviour(myAgent, requestMsg);
                        ((SequentialBehaviour) parent).addSubBehaviour(((HandleAdmisionExclusionBehaviour) parent).requestBehaviour);
                    }
                }
                else if (cs.getTypeName().equals(SLVocabulary.NOT))
                {
                    if (seleccion == 1)
                    {
                        //La persona indicada NO esta en la universidad
                        System.out.println("  /*/ La persona indicada no esta en la universidad, pediremos su admision...");
                        //Obtener los detalles de la persona
                        Admitida adm = (Admitida)o.toObject(cs.getAbsObject(SLVocabulary.NOT_WHAT));
                        Persona p = (Persona) adm.getPersona();
                        Admitir ad = new Admitir();
                        ad.setPersona(p);
                        Action a = new Action();
                        a.setActor(((SecretarioAgent) myAgent).universidad);
                        a.setAction(ad);
 
                        //Crear un mensaje ACL request para pedir la accion que hemos construido
                        ACLMessage requestMsg = new ACLMessage(ACLMessage.REQUEST);
                        requestMsg.addReceiver(((SecretarioAgent) myAgent).universidad);
                        requestMsg.setLanguage(FIPANames.ContentLanguage.FIPA_SL0);
                        requestMsg.setOntology(UniversidadOntology.ONTOLOGY_NAME);
                            // Escribir la accion en el mensaje
 
                            try
                        {
                                myAgent.getContentManager().fillContent(requestMsg, a);
                        } catch (Exception pe) {}
                        //Crear y añadir un comportamiento para pedirle al UniversidadAgent la admision
                        //de la persona p siguiendo el protocolo FIPA-Request
                        ((HandleAdmisionExclusionBehaviour) parent).requestBehaviour = new RequestAdmisionExclusionBehaviour(myAgent, requestMsg);
                        ((SequentialBehaviour) parent).addSubBehaviour(((HandleAdmisionExclusionBehaviour) parent).requestBehaviour);
                    }
                    if (seleccion == 2)
                    {
                        System.out.println("  /*/ La persona indicada no esta admitida en la universidad, no es posible realizar la exclusion.");
                    }
                }
                else
                {
                    //Respuesta inesperada recibida del SecretarioAgent
                    // Informar al usuario
                    System.out.println("  /*/ Respuesta inesperada del SecretarioAgent");
                }
 
            } // Fin del try
            catch (Codec.CodecException fe) {
                System.err.println("FIPAException al llenar/extraer Msgcontent:" + fe.getMessage());
            }
            catch (OntologyException fe) {
                System.err.println("OntologyException en getRoleName:" + fe.getMessage());
            }
        }
 
        protected void handleNotUnderstood(ACLMessage msg)
        {
            System.out.println("  /*/ La petición de comprobación no ha sido entendida por el SecretarioAgent");
        }
 
 
    }
 
 
    /**
        Este comportamiento encapsula la peticion de admision o exclusion
        de la persona indicada en la universidad.
        Esto se hace siguiendo el protocolo de interaccion  FIPA-Request
    */
    class RequestAdmisionExclusionBehaviour extends SimpleAchieveREInitiator {
        // Constructor
        public RequestAdmisionExclusionBehaviour(Agent myAgent, ACLMessage requestMsg){
            super(myAgent, requestMsg);
            requestMsg.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST);
        }
 
        protected void handleAgree(ACLMessage msg)
        {
            System.out.println("  /*/ Requisitos superados. Esperando que se complete la operacion...");
        }
        protected void handleInform(ACLMessage msg)
        {
            try
            {
                Done d = (Done)myAgent.getContentManager().extractContent(msg);
                Action a = (Action)d.getAction();
                Persona p = null;
                if (a.getAction() instanceof Admitir)
                {
                    Admitir ad = (Admitir) a.getAction();
                    p = ad.getPersona();
                    System.out.println("  /*/ Admision completada con exito. " + p.getNombre() + "!!");
                }
                else
                {
                    if (a.getAction() instanceof Excluir)
                    {
                        Excluir ex = (Excluir) a.getAction();
                        p = ex.getPersona();
                        System.out.println("  /*/ Exclusion completada con exito.  " + p.getNombre() + "!!");
                    }
                }
            }
            catch (Exception fe)
            {
                System.out.println(myAgent.getName() + ": Error handling the engagement action.");
                System.out.println(fe.getMessage().toString());
            }
        }
        protected void handleFailure(ACLMessage msg)
        {
            try
            {
                ErrorAdmision pred = (ErrorAdmision)myAgent.getContentManager().extractContent(msg);
                Motivo m = pred.getMOTIVO();
                System.out.println("  /*/ Admision fallida por el siguiente motivo : " + m.getMotivo());
            }
            catch (Codec.CodecException fe){
                System.err.println("FIPAException reading failure reason: " + fe.getMessage());
            }
            catch (OntologyException oe){
                System.err.println("OntologyException reading failure reason: " + oe.getMessage());
            }
        }
        protected void handleRefuse(ACLMessage msg)
        {
            System.out.println("  /*/ Admision rechazada");
            //Obtener el motivo del rechazo y comunicarselo al usuario
            try{
                AbsContentElementList list =(AbsContentElementList)myAgent.getContentManager().extractAbsContent(msg);
                AbsPredicate absPred = (AbsPredicate)list.get(1);
                System.out.println("  /*/ El motivo es: " + absPred.getTypeName());
            }
            catch (Codec.CodecException fe){
                System.err.println("FIPAException reading refusal reason: " + fe.getMessage());
            }
            catch (OntologyException oe){
                System.err.println("OntologyException reading refusal reason: " + oe.getMessage());
            }
        }
    }
 
 
    // VARIABLES LOCALES DEL AGENTE
    AID universidad; // AID del agente al que se enviaran las peticiones de admision de la universidad
 
 
    // AGENT SETUP
    protected void setup() {
 
        // Registrar el codec para el lenguaje SL0
        getContentManager().registerLanguage(new SLCodec(), FIPANames.ContentLanguage.FIPA_SL0);
 
        // Registrar la ontologia usada por esta aplicacion
        getContentManager().registerOntology(UniversidadOntology.getInstance());
 
        //Obtener del usuario el nombre del agente al que se enviaran
        //las peticiones de admision
        try {
            BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
 
            System.out.print("  Introduce el nombre de la universidad de la que soy secretario --> ");
            String name = buff.readLine();
            universidad = new AID(name, AID.ISLOCALNAME);
 
        }
        catch (IOException ioe) {
            System.err.println("Error I/O: " + ioe.getMessage());
        }
 
        //Crear y añadir el comportamiento principal de este agente
          addBehaviour(new HandleAdmisionExclusionBehaviour(this));
    }
}
 


UniversidadAgent.java
import jade.proto.SimpleAchieveREResponder;
 
import jade.core.*;
import jade.core.behaviours.*;
 
import jade.domain.*;
 
import jade.content.lang.Codec;
import jade.content.*;
import jade.content.abs.*;
import jade.content.onto.*;
import jade.content.onto.basic.*;
import jade.content.lang.sl.*;
 
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
 
import universidadOntology.*;
 
import jade.content.onto.basic.*;
import jade.util.leap.*;
import java.util.Random;
 
 
public class UniversidadAgent extends Agent {
 
    // COMPORTAMIENTOS DEL AGENTE
    /**
        Este comportamiento maneja todas las queries sobre gente que pertenece a la Universidad siguiendo el protocolo FIPA-Query
    */
    class HandleUniversidadQueriesBehaviour extends SimpleAchieveREResponder {
        /**
            Constructor para la clase <code>HandleUniversidadQueriesBehaviour</code>
 
            @param myAgent El agente al que pertenece este comportamiento
        */
        //El comportamiento solo manejará mensajes que sigan el protocolo FIPA-QUERY y la ontología UniversidadOntology
        public HandleUniversidadQueriesBehaviour(Agent myAgent){
            super(myAgent, MessageTemplate.and(
                                                MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_QUERY),
                                                MessageTemplate.MatchOntology(UniversidadOntology.ONTOLOGY_NAME)));
        }
 
        /**
            Este metodo se ejecuta cuando se recibe un mensaje QUERY-IF o QUERY-REF
 
            @param msg El mensaje QUERY recibido
            @return El mensaje ACL que devolvemos como respuesta
            @see jade.proto.FipaQueryResponderBehaviour
        */
        public ACLMessage prepareResponse(ACLMessage msg){
 
            ACLMessage reply = msg.createReply();
 
            // El mensaje QUERY puede ser un QUERY-REF. En este caso responder
            // con NOT_UNDERSTOOD
 
            if (msg.getPerformative() != ACLMessage.QUERY_IF){
                reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
                  String content = "(" + msg.toString() + ")";
                reply.setContent(content);
                return(reply);
            }
 
            try {
                //Obtener el predicado cuya veracidad se cuestiona
                Predicate pred = (Predicate)myAgent.getContentManager().extractContent(msg);
                if (!(pred instanceof Admitida)) {
                // Si el predicado por el que se pregunta si es verdad no es un ADMITIDA
                //contestar con NOT-UNDERSTOOD
                    reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
                      String content = "(" + msg.toString() + ")";
                    reply.setContent(content);
                    return(reply);
                }
                // Respuesta (Es un query-if preguntando por un predicado admitida)
                reply.setPerformative(ACLMessage.INFORM);
                Admitida adm = (Admitida)pred;
                Persona p = adm.getPersona(); //Obtenemos la persona asociada a ese predicado
                if (((UniversidadAgent) myAgent).estaEnUniversidad(p))  //Comprobamos si ya esta admitido en la Universidad
                {
                    reply.setContent(msg.getContent());
                }
                else
                {     // Si la comprobacion da resultado negativo
                    // Crear un objeto representando el hecho de que el predicado ADMITIDA no es cierto
 
                    Ontology o = getContentManager().lookupOntology(UniversidadOntology.ONTOLOGY_NAME);
                    AbsPredicate not = new AbsPredicate(SLVocabulary.NOT);
                      not.set(SLVocabulary.NOT_WHAT, o.fromObject(adm));
                        myAgent.getContentManager().fillContent(reply, not);
                }
            }
            catch (Codec.CodecException fe) {
                System.err.println(myAgent.getLocalName()+" Error al llenar/extraer contenido. Motivo:" + fe.getMessage());
            }
            catch (OntologyException oe){
                System.err.println(myAgent.getLocalName()+" getRoleName() ha fallado. Motivo:" + oe.getMessage());
            }
 
            return (reply);
 
        } // FIN del metodo handleQueryMessage()
 
    } // FIN del comportamiento HandleUniversidadQueriesBehaviour
 
 
    /**
        Este comportamiento maneja una única acción de ligación/exclusión que ha sido
        requerida siguiendo el protocolo FIPA-Request
    */
    class HandleAdmisionExclusionBehaviour extends SimpleAchieveREResponder {
 
      /**
          Constructor para la clase <code>HandleAdmisionExclusionBehaviour</code>.
 
          @param myAgent El agente al que pertenece este comportamiento
          @param requestMsg El mensaje ACL en el que se especifica qué acción de ligación ha sido requerida
      */
      public HandleAdmisionExclusionBehaviour(Agent myAgent, MessageTemplate m){
            super(myAgent,m );
      }
 
      /**
        Este método implementa la interfaz <code> FipaRequestResponderBehaviour.Factory</code>
        Será llamado dentro de un <code> FipaRequestResponderBehaviour</code>
        cuando una acción de ligación/exclusión es requerida para instanciar un nuevo
          <code>HandleEngageBehaviour</code> para manejar la acción requerida
 
          @param msg El mensaje ACL en el que se especifica qué acción de ligación/exclusión ha sido requerida
      */
    /**
    Este método maneja la acción de ligación/exclusión
     */
 
 
        public ACLMessage prepareResultNotification(ACLMessage request, ACLMessage response)
        {
        //Preparar un ACLMessage dummy usado para crear el contenido de todos los mensajes de respuesta
           ACLMessage msg = request.createReply();
 
            try
            {
                //Obtener la accion requerida
                Action a = (Action)myAgent.getContentManager().extractContent(request);
                Persona p=null;
                int result = 0;
                if ( a.getAction() instanceof Admitir)
                {
                    Admitir ad = (Admitir) a.getAction();
                    p = ad.getPersona();
 
                    // Llevar a cabo la acción de ligación
                    result = ((UniversidadAgent) myAgent).admitir(p);
                }
                else
                {
                    if ( a.getAction() instanceof Excluir)
                    {
                        Excluir ex = (Excluir) a.getAction();
                        p = ex.getPersona();
                        Persona per = obtenerPersona(p.getDni());
                        p.setNombre(per.getNombre());
 
                        //Llevar a cabo la exclusión
                        result = ((UniversidadAgent) myAgent).excluir(p);
                    }
                }
                // Respuesta según el resultado
                if (result > 0)
                {
                    // OK --> INFORM action
                    Done d = new Done();
                    d.setAction(a);
                    myAgent.getContentManager().fillContent(msg, d);
                    msg.setPerformative(ACLMessage.INFORM);
                }
                else
                {
                    // NOT OK --> FAILURE
                    ErrorAdmision ead = new ErrorAdmision();
                    Motivo m = new Motivo();
                    m.setMotivo("No hay mas plazas para esta universidad");
                    ead.setMOTIVO(m);
                    myAgent.getContentManager().fillContent(msg, ead);
                    msg.setPerformative(ACLMessage.FAILURE);
                }
 
            }
            catch (Exception fe)
            {
                System.out.println(myAgent.getName() + ": Error manejando la peticion.");
                System.out.println(fe.getMessage().toString());
            }
            //Este mensaje es el que se le envía al agente AlumnoAgent, utiliza como lenguaje de contenido SL
            System.out.println(msg);
 
            return msg;
    }
 
 
    public ACLMessage prepareResponse(ACLMessage request)
    {
            //Preparar un ACLMessage dummy usado para crear el contenido de todos los mensajes de respuesta
            ACLMessage temp = request.createReply();
 
            try{
                // Obtener la acción requerida
                Action a = (Action)getContentManager().extractContent(request);
                Persona p = null;
                if ( a.getAction() instanceof Admitir)
                {
                    Admitir ad = (Admitir) a.getAction();
                    p = ad.getPersona();
                }
                else
                {
                    if ( a.getAction() instanceof Excluir)
                    {
                        Excluir ex = (Excluir) a.getAction();
                        p = ex.getPersona();
                    }
                }
                // Generamos un número aleatorio que representa la nota de corte de la universidad
        // Si >= notaCorte --> AGREE, sino REFUSE y exit
        int notaCorte = (int) (Math.random()*5)+5;
                if (p.getNota() >= notaCorte)
                {
                    // AGREE a llevar a cabo la acción de ligación/exclusión sin
                    // ninguna condicion especial
                    ContentElementList l = new ContentElementList();
                    l.add(a);
                    l.add(new TrueProposition());
                    getContentManager().fillContent(temp, l);
                    temp.setPerformative(ACLMessage.AGREE);
                }
                else
                {
                    ContentElementList l = new ContentElementList();
                    l.add(a);
                    l.add(new NoSuperaNota());
                    getContentManager().fillContent(temp, l);
                    temp.setPerformative(ACLMessage.REFUSE);
                }
 
            } catch (Exception fe){
                fe.printStackTrace();
                System.out.println(getName() + ": Error manejando la accion de admision.");
                System.out.println(fe.getMessage().toString());
            }
 
            return temp;
        }
    }
 
 
    // VARIABLES LOCALES DEL AGENTE
    private List admitidos;    // La gente que esta admitida en la universidad
    private int numPlazas;
 
 
    // CONSTRUCTOR DEL AGENTE
    public UniversidadAgent(){
        super();
 
    }
 
    // AGENT SETUP
    protected void setup()
    {
        Object[]args = getArguments();
        if (args != null && args.length == 1)
        {
            admitidos = new ArrayList();
            numPlazas = Integer.parseInt((String)args[0]);
        }
        else
        {
            System.out.println("\n\nDebe indicar el número de plazas de la universidad");
            System.exit(0);
        }
 
        System.out.println("Este es el UniversidadAgent, a la espera de peticiones de alumnos para matricularse...");
        System.out.println("\nEn este momento quedan " + numPlazas + " plazas ");
        // Registrar el codec para el lenguaje SL0
        getContentManager().registerLanguage(new SLCodec(), FIPANames.ContentLanguage.FIPA_SL0);
 
        // Registrar la ontologia usada por esta aplicacion
        getContentManager().registerOntology(UniversidadOntology.getInstance());
 
 
        // Crear y añadir el comportamiento que maneja las REQUEST usando la Universidad-ontology
        MessageTemplate mt = MessageTemplate.and(
                MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST),
                MessageTemplate.MatchOntology(UniversidadOntology.ONTOLOGY_NAME));
          HandleUniversidadQueriesBehaviour b = new HandleUniversidadQueriesBehaviour(this);
          HandleAdmisionExclusionBehaviour c = new HandleAdmisionExclusionBehaviour(this, mt);
          addBehaviour(b);
          addBehaviour(c);
    }
 
    // METODOS DEL AGENTE
    //Si el array de personas admitidas universidad esta vacio,nos respondera que la persona en cuestion
      //no esta registrada en la universidad
 
    boolean estaEnUniversidad(Persona p)
    {
        boolean admitido = false;
        Iterator i = admitidos.iterator();
        while (i.hasNext()){
            Persona adm = (Persona) i.next();
            if (p.getDni().compareTo(adm.getDni()) == 0)
                  {
                admitido = true;
                break;
            }
        }
 
        return admitido;
    }
 
    Persona obtenerPersona(String dni)
    {
        Persona admitido = null;
        Iterator i = admitidos.iterator();
        while (i.hasNext()){
            Persona adm = (Persona) i.next();
            if (dni.compareTo(adm.getDni()) == 0)
                  {
                admitido = adm;
                break;
            }
        }
 
        return admitido;
    }
 
    int admitir(Persona p)
    {
        if ( admitidos.size() == numPlazas )
            return (-1); // No hay mas plazas
        else
        {
            admitidos.add(p);
            if ((numPlazas - admitidos.size()) != 1)
                System.out.println("\nTras el registro quedan " + (numPlazas - admitidos.size()) + " plazas libres \n");
            else
                System.out.println("\nTras el registro queda " + (numPlazas - admitidos.size()) + " plaza libres \n");
            return (1);
        }
    }
 
 
 
 
    int excluir(Persona p)
    {
        int result = -1;
        Iterator i = admitidos.iterator();
        while (i.hasNext()){
            Persona adm = (Persona) i.next();
            if (p.getDni().compareTo(adm.getDni()) == 0)
              {
                admitidos.remove(adm);
                if ((numPlazas - admitidos.size()) != 1)
                    System.out.println("\nTras la exclusion quedan " + (numPlazas - admitidos.size()) + " plazas libres \n");
                else
                    System.out.println("\nTras la exclusion queda " + (numPlazas - admitidos.size()) + " plaza libre \n");
                result = 1;
                break;
            }
        }
        return result;
    }
 
 
}
 



Recomendaciones:
  • Crear una carpeta dentro del directorio examples de jade con el nombre Universidad.
  • Generar, en dicha carpeta, con Protégé la ontología fijándose muy bien en los nombres, poniendo mayúsculas donde hay mayúsculas y minúsculas donde hay minúsculas.
  • Una vez generada la ontología, compilar todos los archivos generados.
  • Insertar las clases SecretarioAgent y UniversidadAgent en la carpeta Universidad y compilarlas.

A continuación se representa la situación que se debería tener:


universidad.jpg

Para ejecutarlo primero lanza un agente "UniversidadAgent" con el número de plazas entre paréntesis.
Ejemplo: java jade.Boot -container uvigo:UniversidadAgent(100)
A continuación lanza un agente "SecretarioAgent".
Ejemplo: java jade.Boot -container secretario:SecretarioAgent





Material de apoyo


Ontología ejemplo policía


Agentes Universidad