Implementación de un SMA de negociación basado en subastas electrónicas Estudiante: Rodolfo de Benito Arango Ingeniería en Informática Consultor: David Isern Alarcón Junio 2009 Agradecimientos A mi hijo Carlos por aceptar que su padre siempre estuviera estudiando. A mi mujer Ana por ayudarme a seguir, a pesar de las dificultades. A ambos por sacrificar tantos fines de semana. A mis padres por su apoyo y ánimos. Al resto de mi familia por su comprensión. A mi consultor David Isern Alarcón, por sus consejos, orientaciones y aliento. A la Universitat Oberta de Catalunya por darme la oportunidad de completar mis estudios y por su estupendo modelo de enseñanza-aprendizaje. -2/106- Índice de contenidos Capítulo 1. ­ Introducción......................................................................................................... 6 1.1. Justificación del PFC y contexto en el que se desarrolla................................................... 6 1.2. Objetivos del PFC ........................................................................................................................... 8 1.2.1. Objetivos generales y alcance.............................................................................................................. 8 1.2.2. Objetivos específicos .............................................................................................................................11 1.3. Planificación de trabajo............................................................................................................ 12 1.3.1. División del trabajo en tareas y estimación de tiempos ........................................................12 1.3.2. Identificación de hitos ..........................................................................................................................14 1.3.3. Planificación temporal..........................................................................................................................15 Capítulo 2. ­ Especificación de requisitos ........................................................................ 17 2.1. Conceptos principales del sistema ....................................................................................... 17 2.1.1. Tipos de subastas....................................................................................................................................17 2.1.2. Agentes........................................................................................................................................................17 2.1.3. Estrategias de negociación .................................................................................................................19 2.1.4. Historial de transacciones ..................................................................................................................20 2.1.5. Problemas a solventar en el sistema ..............................................................................................20 2.2. Diagrama de casos de uso........................................................................................................ 21 2.3. Descripción textual de casos de uso..................................................................................... 21 2.3.1. Registrar subasta ....................................................................................................................................22 2.3.2. Determinar ganador ..............................................................................................................................22 2.3.3. Bajar precio ...............................................................................................................................................22 2.3.4. Crear compra ............................................................................................................................................23 2.3.5. Pujar .............................................................................................................................................................23 2.3.6. Localizar subasta ....................................................................................................................................23 Capítulo 3. ­ Especificación del SMA .................................................................................. 24 3.1. Modelo de roles ........................................................................................................................... 24 3.2. Modelo de entorno ..................................................................................................................... 26 3.3. Modelo de tareas......................................................................................................................... 28 3.4. Modelo de ontologías ................................................................................................................ 29 3.5. Modelo de coordinación........................................................................................................... 30 3.5.1. Negociación subastador inglesa y Comprador...........................................................................30 3.5.2. Negociación subastador holandesa y Comprador ....................................................................30 3.5.3. Suscripción comprador y subastador ............................................................................................31 3.5.4. Búsqueda de subastas. Comprador ‐ Buscador ‐ Casa de subastas...................................32 Capítulo 4. ­ Implementación............................................................................................... 34 4.1. Diagrama de clases .................................................................................................................... 34 4.2. Implementación de los agentes ............................................................................................. 35 4.3. Comunicación entre agentes................................................................................................... 35 4.4. Implementación de los comportamientos (behaviours) .............................................. 36 4.4.1. Comportamientos de subastadores ................................................................................................36 4.4.2. Comportamientos de compradores ................................................................................................37 4.4.3. Comportamientos que inician una petición ................................................................................37 4.4.4. Comportamientos que responden a una petición ....................................................................38 4.5. Implementación de las estrategias....................................................................................... 38 4.5.1. Interfaces utilizados en las estrategias .........................................................................................38 4.5.2. Clases que implementan el interface ICfgApuesta ...................................................................38 -3/106- 4.5.3. Clases que implementan el interface ICfgSubasta ....................................................................38 4.6. Clases de información manejada en la subasta ................................................................ 38 4.7. Estructura de paquetes............................................................................................................. 39 4.8. Librerías utilizadas .................................................................................................................... 40 4.9. Distribución final........................................................................................................................ 40 Capítulo 5. ­ Ejecución ............................................................................................................ 41 5.1. Ejecución del SMA....................................................................................................................... 41 5.2. Test de ejecución ........................................................................................................................ 41 5.2.1. Muestra de flujo de mensajes en el test de la subasta inglesa.............................................44 5.2.2. Muestra de intercambio de mensajes de negociación entre subastador y compradores en el test de la subasta inglesa .........................................................................................45 5.2.3. Muestra de flujo de mensajes en el test de la subasta holandesa ......................................46 5.2.4. Muestra de intercambio de mensajes de negociación entre subastador y compradores en el test de la subasta holandesa...................................................................................47 5.2.5. Muestra de mensajes entre el agente Subastador, el agente DF y el agente CasaSubastas.........................................................................................................................................................48 5.2.6. Rondas y pujas obtenidas en el test de la subasta inglesa ....................................................49 5.2.7. Rondas y pujas obtenidas en el test de la subasta holandesa .............................................49 5.3. Sistema de logging...................................................................................................................... 50 Capítulo 6. ­ Conclusiones y propuestas de mejora ...................................................... 51 Anexo A. Clases Java implementadas ................................................................................ 55 Clase AgenteBase ................................................................................................................................................55 Clase AgenteCasaSubastas ..............................................................................................................................57 Clase AgenteSubastador...................................................................................................................................64 Clase AgenteBuscador.......................................................................................................................................67 Clase AgenteComprador ..................................................................................................................................68 Clase SubastadorBehaviour............................................................................................................................72 Clase SubastadorHolandesaBehaviour......................................................................................................73 Clase SubastadorInglesaBehaviour.............................................................................................................76 Clase CompradorInglesaIncrementalBehaviour ...................................................................................79 Clase CompradorHolandesaNRondasBehaviour...................................................................................82 Clase CompradorHolandesaIncrementoDinamicoBehaviour .........................................................84 Clase BuscadorBehaviourInitiator ..............................................................................................................87 Clase CompradorSuscribirBehaviourInitiator .......................................................................................90 Clase SubastadorTransaccionesBehaviourInitiator ............................................................................91 Clase BuscadorBehaviourResponder.........................................................................................................92 Clase CasaSubastasBusquedasBehaviourResponder..........................................................................93 Clase SubastadorSuscribirBehaviourResponder ..................................................................................94 Clase CasaSubastasTransaccionesBehaviourResponder...................................................................96 Clase ICfgApuesta ..............................................................................................................................................97 Clase ICfgSubasta ................................................................................................................................................98 Clase IncrementalCfgImpl ...............................................................................................................................98 Clase ApuestaUnicaNRondasCfgImpl.........................................................................................................99 Clase ApuestaUnicaIncrementoDinamicoCfgImpl............................................................................. 101 Clase SubastaHolandesaImpl...................................................................................................................... 103 Clase SubastaInglesaImpl............................................................................................................................. 103 Clase Subasta ..................................................................................................................................................... 104 Clase Transacción ............................................................................................................................................ 106 -4/106- Índice de figuras Figura 1. Remote Agent Management de JADE.................................................................... 9 Figura 2. Sniffer de JADE mostrando el flujo de mensajes entre 3 agentes.......................... 9 Figura 3. Instrospector de JADE mostrando los mensajes recibidos por un agente y el comportamiento que está ejecutando ........................................................................... 10 Figura 4. Log Manager de JADE ........................................................................................ 10 Figura 5. Diagrama de Gantt de las tareas del proyecto...................................................... 16 Figura 6. Diagrama de casos de uso .................................................................................... 21 Figura 7. Diagrama de modelo de roles ............................... ¡Error!Marcador no definido. Figura 8. Diagrama de actividad subasta inglesa ................................................................ 28 Figura 9. Diagrama de actividad subasta holandesa............................................................ 28 Figura 10. Diagrama de conceptos ...................................................................................... 29 Figura 11. Diagrama de secuencia del protocolo de interacción de la subasta inglesa ...... 30 Figura 12. Diagrama de secuencia del protocolo de interacción de la subasta holandesa .. 31 Figura 13. Diagrama de secuencia del protocolo de suscripción mantenido entre Comprador y Subastador ................................................................................................................. 31 Figura 14. Diagrama de secuencia del protocolo FIPA-Brokering ..................................... 32 Figura 15. Diagrama de secuencia del protocolo FIPA-Query que actúa como subprotocolo en el proceso de búsqueda de una subasta.................................................................... 33 Figura 16. Diagrama de clases del SMA............................................................................. 34 Figura 17. FIPA Contract Net Interaction Protocol ............................................................ 37 Figura 18. Estructura de paquetes utilizada en el desarrollo del SMA ............................... 39 Figura 19. Intercambio de mensajes en subasta inglesa...................................................... 44 Figura 20. Intercambio de mensajes en subasta holandesa ................................................. 46 -5/106- Capítulo 1. - Introducción 1.1. Justificación del PFC y contexto en el que se desarrolla El proyecto pertenece al ámbito de la Inteligencia Artificial y, más concretamente, al ámbito de los Sistemas Multiagente o SMA. Entendiendo como SMA [1]: "Un conjunto de agentes autónomos inteligentes que se comunican para resolver un problema de manera conjunta. Cuando los componentes de este tipo de sistemas quieren cooperar en la resolución del problema, se habla de un conjunto de agentes colaborativos.". En cuanto a los agentes que integran un SMA, hay muchas definiciones al respecto. La FIPA [2] (Foundation for Intelligent Physical Agents) los define de la siguiente manera: "Un agente es una entidad de software encapsulado con su propio estado, conducta, hilo de control y la habilidad para interactuar y comunicarse con otras entidades (gente, otros agentes o sistemas legados)”. Los agentes se definen como [3]: “...hardware o (más usualmente) sistema de computación que posea las siguientes propiedades: - autonomía: opera sin intervención directa de los humanos u otros programas, y tiene algún tipo de control sobre sus acciones o estado interno; - habilidad social: interactúan con otros agentes a través de un lenguaje de comunicación; - reactividad: perciben su entorno (mundo físico, usuario a través de interfaz gráfica, agentes, Internet) y responden a cambios que ocurren en él; - pro-actividad: exhiben comportamiento dirigido por objetivos, tomando la iniciativa.” El campo de actuación de los SMA comprende, entre otros [4]: • Flujos de trabajo y gestión de procesos de negocio. Como por ejemplo el SMA utilizado por SCA Packaging para explorar diferentes estrategias encaminadas a reducir los niveles de stocks sin comprometer los tiempos de reparto, que consigue reducir los niveles de stock en almacén un 35%. • Reputación y confianza. Aportan nuevas técnicas para expresar el razonamiento sobre la reputación y la confianza a nivel individual y social para posibilitar la interacción en entornos abiertos y dinámicos. • Creación y gestión de Organizaciones Virtuales en Grid computing. En lo que se refiere la gestión y desarrollo de procedimientos y métodos para la automatización de creación de Organizaciones Virtuales (VOs), gestión y disolución. -6/106- • Coordinación y reubicación de recursos. En la gestión autónoma y coordinada de recursos distribuidos. • Negociación. Aportando estrategias y protocolos que establecen reglas de negociación así como los propios mecanismos de negociación. Determinando qué algoritmo de negociación es el más adecuado bajo determinadas circunstancias. • Aprendizaje y optimización. Aplicado por ejemplo al campo de la logística en sistemas de optimización de transporte basados en coste, como es el caso de Adaptive Transportation Networks cuyos agentes negocian utilizando un protocolo similar al utilizado en las subastas. • Trazabilidad. Aportando mecanismos para la conocer la traza de cómo se ha logrado alcanzar determinado resultado identificando los servicios que lo han producido. El presente proyecto se centra en el ámbito del comercio electrónico en la modalidad de agentes de subasta (auction bots) [5]: "Agents that can run, and participate in, online auctions for goods." Lo que se pretende es lograr es llevar a cabo todo el proceso de negociación de las subastas sin intervención humana, por medio de sus agentes representantes. De tal manera que un vendedor parametrice la subasta a realizar (tipo de subasta, precio mínimo, tiempo de subasta, etc.) y genere un agente vendedor que lo representará en la subasta. Por otra parte, los compradores generarán sus agentes parametrizados acorde al objeto de la subasta y a la estrategia a seguir en la misma. A partir de ahí se produce la interacción "automática" entre agentes compradores y vendedores de la subasta, según sus modelos de comportamiento y estrategias de negociación, hasta el momento en que ésta concluya. Al finalizar, los agentes tanto compradores como vendedores informarán de los resultados e iniciarán los procesos necesarios tras la adjudicación del producto de la subasta, en caso de que esta adjudicación se produzca. En cuanto a los modelos de subasta, los contemplados en el sistema corresponden a la tipología de subastas abiertas y más concretamente a las subastas al alza (inglesa) y las subastas a la baja (holandesa). En el Capítulo 2 se explican en que consisten cada una de ellas. En este campo de los sistemas multiagente de subastas existen bastantes estudios sobre todo en el contexto de la subasta doble continua o CDA y se han utilizado algunos de ellos [6, 7, 8] como fuente para obtener información sobre las estrategias de negociación de los agentes "tipo". En cuanto a la justificación del proyecto, en gran parte se debe al interés del estudiante de obtener una visión práctica del funcionamiento de los SMA y adquirir una experiencia básica en la implementación de estos sistemas utilizando Java. -7/106- 1.2. Objetivos del PFC 1.2.1. Objetivos generales y alcance El objetivo general del proyecto es adquirir una experiencia en el modelado e implementación de sistemas multiagente (SMA) de negociación. Más concretamente, la negociación se realizará en un entorno de subastas electrónica. En un principio, el modelado de la especificación se pensó realizarla con IDK [9] (INGENIAS Development Kit) pero se descartó debido fundamentalmente a problemas de tiempo para hacer una especificación tan detallada como exige el IDK, hecho ya previsto por el consultor del proyecto. Motivo por el cual se buscó una metodología menos exigente pero que a la vez reflejara claramente los requisitos y modelara el SMA a alto nivel. La metodología que más se adapta a estas necesidades está definida en el artículo "Una Aproximación Metodológica para la Construcción de Modelos de simulación Basados en el Paradigma Multi-Agente" [10] y, en líneas generales, ha sido la que se ha seguido en este proyecto. El entorno de desarrollo del proyecto se realizará en Eclipse y la ejecución del SMA se llevará a cabo con JADE [11,12] (Java Agent Development Framework) un entorno de desarrollo y ejecución de agentes basado en Java, que cumple la especificación FIPA, y que simplifica la implementación de aplicaciones distribuidas. JADE proporciona: • Un API Java para desarrollar los agentes. • Un contenedor o entorno de ejecución en el que "viven" los agentes (similar al concepto de contenedor EJB en J2EE). • Un conjunto de herramientas gráficas gestión y depuración de agentes, entre los que se encuentran: o RMA o Remote Agent Management. Desde él se pueden iniciar el resto de herramientas gráficas y gestionar los agentes. -8/106- Figura 1. Remote Agent Management de JADE o Snnifer para capturar el flujo de mensajes entre los agentes. Figura 2. Sniffer de JADE mostrando el flujo de mensajes entre 3 agentes -9/106- o Instrospector para acceder a la cola de mensajes enviados y recibidos por un agente y a los comportamientos que está ejecutando. Figura 3. Instrospector de JADE mostrando los mensajes recibidos por un agente y el comportamiento que está ejecutando o JADE Log Manager para ver los logs que se producen en la ejecución del SMA. Figura 4. Log Manager de JADE -10/106- El alcance del proyecto se centra en la capa de negocio y no incluye un entorno gráfico para el interfaz del usuario ni persistencia de datos. Como futura mejora del proyecto se podría realizar un interfaz del usuario Web y utilizar una solución de persistencia como por ejemplo Hibernate [13] o iBatis [14]. De tal manera que combinara J2EE con el entorno de ejecución de JADE. 1.2.2. Objetivos específicos Los objetivos específicos del proyecto consisten en: • Modelar la especificación de un SMA utilizando la metodología definida en "Una Aproximación Metodológica para la Construcción de Modelos de simulación Basados en el Paradigma Multi-Agente" [15] • Utilizar JADE como entorno de ejecución y comunicación de un SMA. • Implementar las clases de test que comprueben el funcionamiento de los agentes y del SMA. • Implementar las clases de los agentes y de sus comportamientos con el fin de lograr un SMA de subastas virtuales con agentes compradores y vendedores capaces de negociar en base a diferentes estrategias. -11/106- 1.3. Planificación de trabajo 1.3.1. División del trabajo en tareas y estimación de tiempos Se ha optado por una división Top-Down de las tareas necesarias para satisfacer los objetivos señalados anteriormente. En la Tabla 1.1 se recogen la división de estructuras del trabajo y sus duraciones estimadas. T01 Definición del plan de trabajo 5 días Elaboración del plan de trabajo del proyecto T01.1 Recogida de documentación básica Obtención de documentación necesaria para 2 días iniciar el estudio del proyecto. Fuente principal Internet T01.2 Propósito del proyecto 1 día Propósito y definición del proyecto T01.3 Objetivos Definición de los objetivos generales y 1 día específicos T01.4 Planificación Descomposición del trabajo en tareas siguiendo 1 día una metodología WBS y planificación temporal de las mismas. T02 Documentación de requisitos del SMA 7 días Especificar los requisitos del SMA modelando los casos de uso en un diagrama general y obteniendo una descripción textual de los casos de uso, con el propósito de identificar qué debe hacer el sistema, cómo y cuándo. Así como una introducción de los conceptos principales del sistema. T02.1 Conceptos principales del sistema Protocolos de subastas, agentes, estrategias de 2 días negociación, el historial de transacciones y previsión de problemas a solventa en el sistema. T02.2 Diagrama de casos de uso Diagrama general de casos de uso que servirá de 1 días base para identificar los requisitos funcionales del sistema. T02.3 Descripción textual de casos de uso 4 días Descripción textual de los casos de uso identificados en el diagrama de casos de uso. Servirán para identificar los agentes del sistema, sus tareas y la interacción entre ellos. 27 T03 Especificación del SMA días Una vez conocidos los requisitos del sistema realizará una especificación del SMA basándose en la Metodología descrita en el Apartado 1.2.1. T03.1 Modelo de roles Identifica los roles o papeles de los agentes 5 días tomando como base el diagrama de casos de uso. T03.2 Modelo de entorno Describe aquellos componentes del sistema que 5 días no son agentes pero que intervienen de una u otra forma en los procesos que llevan a cabo los agentes. -12/106- T03.3 Modelo de tareas T03.4 Modelo de razonamiento y aprendizaje T03.5 Modelo de ontología T03.6 Modelo de coordinación T04 Detalla el funcionamiento de cada rol mediante la descomposición de las tareas en secuencias de actividades y su representación en un diagrama de actividad. Engloba las creencias, objetivos, capacidades y decisiones de cada rol y las relaciona con las actividades que debe efectuar. Se representa gráficamente mediante diagramas de flujo. Representar los conceptos de la ontología (estructura y significado de los conceptos principales del sistema) y sus relaciones mediante un diagrama de clases UML. Utiliza los diagramas de secuencias UML para representar las interacciones entre los roles y las etapas que las componen. Implementación SMA 4 días 9 días 2 días 2 días 34 días Implementación en JADE del SMA según las especificaciones de la tarea T03. T04.1 Crear despliegue Definir la configuración de despliegue que será utilizada para lanzar los agentes. Crear las clases necesarias para el funcionamiento del SMA. Integrar el código IDK con las clases de la tarea T04 y refinar el código para que funcione correctamente. T04.2 Implementar clases del SMA T04.3 Refinar el código. T05 Redacción memoria del proyecto Redacción de la memoria del proyecto T05.1 Documentar requisitos SMA Redactar los requisitos del SMA en base al trabajo obtenido en la tarea T02. T05.2 Documentar especificación SMA Redactar la especificación del SMA en base al trabajo obtenido en la tarea T03. T05.3 Documentar implementación del SMA Redactar la implementación del SMA en base al trabajo obtenido en la tarea T04. T05.4 Conclusiones, mejoras, referencias y Completar la memoria añadiendo las bibliografía conclusiones, las mejoras posibles, las referencias y la bibliografía. T05.5 Revisiones Realizar las modificaciones necesarias en la memoria en base a las indicaciones del consultor. -13/106- 3 días 25 días 6 días 31 días 5 días 7 días 7 días 7 días 5 días 20 T06 Test días Elaboración de los juegos de pruebas necesarios para probar el correcto funcionamientos de los agentes y del SMA implementado. T06.1 Test de agentes 10 Crear un juego de pruebas que verifique el días funcionamiento de los agentes tipo que intervienen en el SMA. T06.2 Test SMA 10 Crear un juego de pruebas que verifique el días funcionamiento del SMA. 10 T07 Elaborar presentación virtual días Elaboración de una presentación PowerPoint que sintetice y exponga el trabajo realizado en el proyecto. 20 T08 Revisiones días Revisiones finales del SMA obtenido, de la memoria y de la presentación. Tabla 1.1. División del trabajo y duración estimada. 1.3.2. Identificación de hitos • PEC 1: entrega Planificación en fecha 8/3/2009. • PEC 2: entrega Requisitos y Especificación del SMA en fecha 12/4/2009. • PEC 3: entrega Implementación del SMA en fecha 17/5/2009. • Entrega final: implementación del SMA, memoria y presentación en fecha 19/6/2009. -14/106- 1.3.3. Planificación temporal En la Tabla 1.2 se muestra la planificación temporal de las tareas con su duración, fechas de comienzo y fechas de fin. En la Figura 1 se muestra el diagrama de Gantt correspondiente a la planificación. Tabla 1.2. Planificación temporal tareas. -15/106- Figura 5. Diagrama de Gantt de las tareas del proyecto. -16/106- Capítulo 2. - Especificación de requisitos En este Capítulo se introducen los conceptos principales del núcleo central del SMA y se especifican los requisitos del SMA modelando los casos de uso en un diagrama general y realizando una descripción textual de los casos de uso más relevantes, con el propósito de identificar las funcionalidades principales del sistema y sus actores. Originalmente, el proyecto no consideraba más agentes que los que directamente intervienen en los procesos de negociación de las subastas, es decir, Agente Subastador y Agente Comprador. Tras la lectura de "A Trustworthy Agent Based Online Auction System" [15] se vio la necesidad de incorporar un agente Casa de subastas y agente Buscador, más adelante se detalla el rol de cada uno de ellos, además de adoptarse un diseño similar para conseguir que el sistema sea abierto a la extensión en cuanto a estrategias de compra se refiere. 2.1. Conceptos principales del sistema 2.1.1. Tipos de subastas Los tipos de subasta que podrá elegir el vendedor corresponden a la tipología de subastas abiertas y más concretamente a las siguientes [16,17]: • Subasta al alza. Pretende fomentar la competencia de los posibles compradores de tal modo que el vendedor establece un precio de salida bajo. Este precio se va incrementando con las sucesivas pujas de modo que se adjudica el objeto de la subasta al participante que haya realizado la puja más alta durante el tiempo de vida de la subasta. El vendedor puede fijar un precio mínimo de tal modo que si al finalizar la subasta la puja máxima no es mayor o igual que el precio mínimo entonces no se producirá la venta o adjudicación. Es la subasta clásica, también conocida como subasta inglesa. • Subasta a la baja. El vendedor fija un precio de salida alto y sucesivamente lo baja hasta que aparece un comprador que acepta el precio momento en el cual se le adjudica el objeto de la subasta. Normalmente el vendedor fija un precio de reserva de tal modo que ese precio será el mínimo al que puede llegar el objeto subastado. También se conoce como subasta holandesa. Nota: en un principio se consideraron las subastas a segundo precio o Vickrey pero se descartaron para no aumentar la complejidad del proyecto. 2.1.2. Agentes En la concepción inicial de este proyecto se consideraron dos agentes con los roles de vendedor o subastador y de comprador. A medida que el proyecto evoluciona se ve la necesidad de crear nuevos tipos de agentes como es el caso de un agente Casa de subastas que registra las subastas activas y los movimientos del historial de transacciones, entre otras cosas, así como de un agente Buscador que localice las subastas activas que subasten un bien determinado de interés para el usuario. -17/106- El sistema trabajará con los tipos de agentes siguiente: • Agente casa de subastas. Puesto en funcionamiento por el sistema, tiene las responsabilidades siguientes: o Mantener la lista de subastas activas y de bienes subastados. o Crear la subastas y el agente subastador cuando se da de alta una nueva en el sistema. o Obtener la lista de subastas activa. o Obtener la lista de bienes que se subastan. Para acotar el problema se considera que no puede haber dos subastas activas que subasten el mismo bien. o Cerrar la subasta cuando concluye. o Responder al agente buscador sobre la búsqueda de una subasta concreta. o Registrar en el historial las transacciones que se produzcan a consecuencia de la interacción entre agentes compradores y vendedores. o Realizar los test de funcionamiento del SMA de subastas. • Agente subastador. Son puestos en funcionamiento por el agente Casa de subastas y configurados previamente con: o El artículo a vender. o El tipo de subasta a realizar: inglesa, holandesa. o El precio de salida. o El precio de reserva. o La fecha de finalización de la subasta. Una vez liberado en el sistema, el agente comprador hará las gestiones necesarias para responder a los mensajes de los compradores, notificar los cambios de precios a los agentes involucrados en la subasta, reducir los precios en caso de la subasta holandesa, determinar el ganador, notificar el ganador y notificar la finalización de la subasta al agente Casa de subastas. • Agente buscador. Actúa de intermediario entre el usuario el agente Casa de subastas para localizar las subastas activas que subasten un bien por el que el usuario está dispuesto a pujar. • Agente comprador. Puesto en funcionamiento por el agente Casa de subastas y configurado con: o El artículo que se pretende comprar. o La puja a realizar. o El precio de reserva (la puja máxima a la puede llegar el agente). o La estrategia a seguir (se detallan en el apartado Estrategias de negociación) -18/106- El agente comprador está vinculado a la subasta establecida en su configuración inicial y se mantendrá en la misma realizando las pujas que considere el agente en base a sus estrategias de negociación y al tipo de subasta. 2.1.3. Estrategias de negociación Las estrategias de negociación [6] determinarán el comportamiento de los agentes en la subasta y serán parametrizadas al crear el agente aunque podrían modificarse dinámicamente según el conocimiento del entorno, lo que permitiría, por ejemplo, que en la subasta inglesa no todos los compradores pujen de la misma forma. Las estrategias seguidas por los agentes y los resultados a los que llevan éstas podrán contrastarse ya que el sistema guardará un historial de transacciones de las subastas. En general, la estrategia del pujador determinará cuánto debe pujar y cuándo hacerlo. Para ello, el sistema contemplará las estrategias siguientes: • Incremental. Estrategia del comprador de la subasta inglesa en la que el agente puja a intervalos regulares incrementando la puja en una cantidad preestablecida al crear el agente. Se puede optar por una de estas dos formas de incrementar la puja: o Nueva puja = puja anterior + incremento. o Nueva puja = puja anterior * incremento. • Apuesta única n rondas. Estrategia del comprador de la subasta holandesa en la que al principio el agente considera pujar en la subasta por el precio configurado en su atributo Puja. Si en el transcurso de la subasta se supera el número de rondas configurado en la estrategia entonces el valor de aceptación de la puja será el de su precio de reserva. • Apuesta única n rondas incremento dinámico. Estrategia del comprador de la subasta holandesa en la que en principio el agente considera pujar en la subasta por el precio configurado en su atributo Puja. Si se supera el número de rondas preestablecido en la estrategia entonces incrementará el valor de aceptación de la puja en una cantidad fija siempre y cuando no llegue al precio de reserva. Por otra parte, se pretende que el SMA a implementar pertenezca abierto a la extensión en el sentido de que sea sencillo implementar nuevas estrategias y configurarlas para que sean utilizadas por los agentes compradores. Por ejemplo, para que en lugar de ser estrategias estáticas, como las comentadas anteriormente, sean dinámicas y reactivas al comportamiento de otros pujadores o al historial de transacciones. Además, en la subasta holandesa podría resultar interesante incluir adaptaciones de estrategias propias de agentes de subastas dobles continuas [7, 8] como por ejemplo la de los Agentes Kaplan, Agentes Zero-Intelligente Plus (ZIP) o Agentes GD. -19/106- 2.1.4. Historial de transacciones El sistema guardará un registro de las transacciones que tienen lugar en las subastas, almacenando información referente al identificador de la subasta, identificador del agente que realizó la transacción, el tipo de transacción, el precio (de puja o de venta) y la fecha. El propósito de este historial es doble, por una parte puede utilizarse como fuente de datos para realizar un estudio sobre el comportamiento de los tipos de agentes en las subastas. Por otra parte puede utilizarse como base de conocimiento para que los agentes compradores y vendedores puedan adaptar su estrategia de negociación. 2.1.5. Problemas a solventar en el sistema En una valoración previa de las cuestiones que deben resolverse en la implementación de este SMA de subastas se pueden identificar los siguientes: • El sistema de suscripciones a las subastas y notificaciones de cambios de precios. Puede solventarse empleando el patrón Observador, de modo que los compradores se suscriben a las subastas de los vendedores y estos podrán notificar eventos de la subasta a todos sus subscriptores. • Pujas simultáneas en la subasta inglesa. Se produce cuando más de un comprador realiza una puja simultáneamente. Puede tomarse como un problema de concurrencia de productor-consumidor, siendo el productor el vendedor y el consumidor el comprador. Se solventa utilizando una cola thread safe para procesar los mensajes de puja que reciba el vendedor, aunque esta funcionalidad ya está incorporada en el propio JADE y por tanto no es necesario implementarla de el sistema. • Colisiones en ofertas realizadas por los compradores en la subasta holandesa. Se produce cuando más de un comprador oferta el mismo precio. Se puede resolver con el mismo sistema que el caso de las pujas simultaneas en la subasta inglesa. Otra solución que puede adoptarse es utilizar un contador de colisiones, establecer un máximo de colisiones permitidas y repetir la subasta hasta que el contador llegue al máximo en cuyo caso se daría como ganador aleatoriamente a una de las pujas ganadoras. -20/106- 2.2. Diagrama de casos de uso En la Figura 6. Diagrama de casos de uso, se identifica el actor Agente CasaDesSubastas que se encarga de poner en marcha los casos de uso Revistar subasta y Crear compra que desencadenan todo el proceso de una subasta. También figuran los agentes Comprador y Subastador y una especialización de este último, el Agente Subastador holandesa que pone en marcha el caso de uso bajar precio (caso particular de este tipo de subastas). Así como el agente Buscador encargado de localizar una subasta en base a un criterio. Figura 6. Diagrama de casos de uso 2.3. Descripción textual de casos de uso En la descripción textual siguiente solo se tendrán en cuenta los casos de uso que no están incluidos en otros puesto que su descripción textual no aporta nada a la documentación de requisitos aunque es importante que figuren en el diagrama de casos de uso para ofrecer una visión de las implicaciones de los casos de uso "principales" (puestos en marcha directamente por un actor). -21/106- 2.3.1. Registrar subasta Caso de uso Actores Precondición Poscondición Descripción Registrar subasta Agente CasaDeSubastas La subasta no está registrada en el sistema La subasta está registrada en el sistema y hay un agente subastador encargado de la venta objeto de la subasta. 1. El Agente CasaDeSubastas crea un Agente Subastador encargado de la subasta. 2. Registra el bien subastado en la lista de bienes subastados. 3. Registra la subasta en la lista de subastas activas: • El identificador de la subasta • La fecha de inicio de la subasta • El identificador del agente subastador • El objeto a subastar • El tipo de subasta a realizar: inglesa, holandesa. • El precio de salida • El precio de venta de reserva Flujo alternativo 2.3.2. Determinar ganador Caso de uso Actores Precondición Poscondición Descripción Determinar ganador Agente Subastador Hay un Agente Subastador encargado de la subasta y, o bien, la subasta es inglesa y ha finalizado, o bien, la subasta es holandesa y hay uno o más compradores que ofertan el precio establecido por el Agente Subastador. La subasta cierra 1. El Agente Subastador comprueba que la puja actual es la ganadora. 2. El Agente Subastador notifica al Agente CasaDeSubastas y a los agentes compradores del resultado de la subasta. 3. El Agente Subastador da por cerrada la subasta y se lo notifica a al Agente CasaDeSubastas. Flujo alternativo 2.3.3. Bajar precio Caso de uso Actores Precondición Poscondición Descripción Bajar precio Agente Subastador El tipo de subasta es holandesa y no ha finalizado El precio del bien subastado se ha reducido 1. El Agente Subastador determina en base a su estrategia que es necesario bajar el precio. 2. Calcula el nuevo precio de la subasta. 3. Notifica el nuevo precio al Agente CasaDeSubastas y a los agentes vendedores suscritos en la subasta. Flujo alternativo -22/106- 2.3.4. Crear compra Caso de uso Actores Precondición Poscondición Descripción Crear compra Agente CasaDeSubastas Hay una subasta en curso de interés para el comprador Se crea un agente comprador suscrito a la subasta 1. Crea un agente Comprador asignándole una estrategia parametrizada de la forma siguiente. Para la subasta inglesa: • La forma de incrementar la puja. • El incremento. • La puja inicial • La puja máxima o reserva. Para la subasta Holandesa: • El incremento • El precio aceptable inicial • El precio aceptable máximo o reserva. • El número de ronda máximo para incrementar el precio aceptable 2. Le asigna una subasta concreta. Flujo alternativo 2.3.5. Pujar Caso de uso Actores Precondición Poscondición Descripción Flujo alternativo Pujar Agente comprador El agente Comprador está suscrito a una subasta. Una nueva puja del agente comprador es notificada al Agente Subastador 1. El agente comprador determina realizar una puja y el importe de la misma según la estrategia seguida por el agente Comprador. 2. El agente Comprador envía un mensaje al Agente Subastador notificando la puja. 3. El Agente Subastador procesa la puja. 4. El Agente Subastador verifica que la puja es correcta y la notifica al Agente CasaDeSubastas y al resto de compradores. 4a. Si la subasta ha finalizado entonces caso de uso Determinar ganador. 2.3.6. Localizar subasta Caso de uso Actores Precondición Poscondición Descripción Localizar subasta Agente Buscador 1. El usuario indica el objeto de subasta que le interesa localizar. 2. El agente Buscador envía un mensaje al Agente CasaDeSubastas con la búsqueda a realizar. 3. El Agente CasaDeSubastas envía un mensaje al Agente Buscador con el resultado de la búsqueda. 4. El Agente Buscador informa textualmente al usuario del resultado de la búsqueda. Flujo alternativo -23/106- Capítulo 3. - Especificación del SMA 3.1. Modelo de roles En este modelo se identificación los roles o papeles de los agentes tomando como base el diagrama de casos de uso. En la Figura 7, se pueden ver los roles de los agentes contemplados en el sistema. El agente CasaDeSubastas está relacionado con 0 o más agentes Subastadores Cada agente Comprador dispone de un agente Buscador el cual solicita al agente CasaDeSubastas la lista de subastas actuales o aquellas en las que se subasta un bien determinado. La relación de uso entre Agente Subastador y Agente Comprador representa la negociación entre ambos que se produce en la subasta. También se puede ver la relación de especialización del agente Subastador Holandesa respecto al agente Subastador. Complementando al diagrama anterior, se describe a alto nivel y en formato tabular el papel que desempeña cada tipo de agente en cuanto a sus objetivos, responsabilidades principales, capacidades e información que requiere para cumplir sus objetivos. Rol Agente Buscador Objetivos Localizar las subastas activas según criterio de búsqueda Responsabilidades Capacidades Enviar mensajes de búsqueda de subastas al Agente CasaDeSubastas Notificar las subastas encontradas al usuario Buscar subastas Información requerida • El "objeto" o bien que quiere localizarse en subasta -24/106- Rol Agente CasaDeSubastas Objetivos Llevar un control de todas las subastas del sistema Responsabilidades • Crear los agentes subastadores • Crear los agentes compradores • Registrar las subastas en el sistema • Notificar la subasta activa de un bien determinado • Eliminar al agente subastador cuando concluya una subasta • Actualizar el Historial de transacciones Creación de agentes y gestión de las subastas Capacidades Información requerida • • • • Rol Agente Subastador Objetivos Vender el objeto de la subasta con el mayor beneficio posible respetando el precio de reserva. • Determinar el ganador. • Notificar ganador. • Notificar nueva oferta a los suscriptores (subasta inglesa) Vender un producto mediante subasta electrónica. Responsabilidades Capacidades Los parámetros de configuración de la subasta. Los parámetros de configuración de los agentes compradores Los parámetros de configuración de los agentes subastadores Las datos de la transacción a registrar. Información requerida • • Rol Agente Subastador Holandesa Objetivos Vender el objeto de la subasta con el mayor beneficio posible respetando el precio de reserva Las mismas que las del Agente Subastador y además la estrategia a seguir a la hora de determinar: • Cuando ofertar el objeto de la subasta a un precio más reducido. • La disminución de precio. Vender un producto mediante subasta electrónica. • Los parámetros de configuración de la subasta (igual que en Agente Subastador) • Las ofertas de compra (pujas) de los vendedores. Responsabilidades Capacidades Información requerida Los parámetros de configuración de la subasta. Las ofertas de compra (pujas) de los vendedores. Rol Agente Comprador Objetivos Comprar el objeto de la subasta al menor precio posible sin superar el precio de reserva. Efectuar las pujas según el tipo de subasta y la estrategia elegida por el comprador. Comprar productos en una subasta electrónica. Responsabilidades Capacidades Información requerida • • • • Los parámetros de configuración del agente. El tipo de subasta. El precio de venta actual. La estrategia a seguir -25/106- 3.2. Modelo de entorno El modelo del entorno describe aquellos componentes del sistema que no son agentes pero que intervienen de una u otra forma en los procesos que llevan a cabo los agentes. Se puede entender como la relación a nivel de flujo de información que se produce entre los agentes y el entorno, identificando las entradas de datos, procesos que se llevan a cabo y las salidas generadas. Componente Entradas Dato • • • • • Precio de compra aceptable (subasta holandesa) Emisor(es) El número de rondas actuales de la subasta El número de rondas máximo para el comprador El precio de compra aceptable actual El precio de compra de reserva El incremento de precio de compra por ronda • • Comprador Subastador Procesos En las subastas holandesas el comprador recalculará el precio de compra aceptable según su estrategia. Para la estrategia Apuesta única n rondas: SI numero rondas actual >= número de rondas máximo para el comprador ENTONCES Precio de compra aceptable=Precio de compra de reserva FIN SI Para la estrategia Apuesta única incremento dinámico: SI numero rondas actual >= número de rondas máximo para el comprador ENTONCES SI precio de compra aceptable + incremento > precio de compra de reserva ENTONCES No se modifica el precio de compra aceptable SI NO Precio de compra aceptable=precio de compra aceptable anterior + incremento FIN SI FIN SI Salidas Dato Receptor(es) El precio de compra aceptable Comprador -26/106- Componente Entradas Dato • • • • Oferta de compra subasta inglesa Emisor(es) La puja actual El precio de reserva El incremento La forma de incrementar la puja • • Comprador Subastador Procesos En la subasta inglesa el comprador determinará si puja o no en una ronda y el valor de la puja en base a su estrategia. Para la estrategia incremental: MIENTRAS (puja<puja actual) SI (tipo de incremento es sumar) ENTONCES puja = puja + incremento SI NO puja = puja * incremento FIN SI FIN MIENTRAS Salidas Dato Receptor(es) La puja de un comprador en una ronda de una subasta Comprador Subastador Componente Entradas Dato Emisor(es) • • • Oferta de venta subasta holandesa El precio de venta actual El precio de venta de reserva El decremento • Subastador Procesos En la subasta holandesa el subastador determinará el nuevo precio de venta ofertado si no hay ofertas de compra en una ronda. nuevo precio de venta = precio de venta actual - decremento SI (nuevo precio de venta>=precio de venta de reserva) ENTONCES precio de venta actual = nuevo precio de venta SI NO terminar subasta FIN SI Salidas Dato Receptor(es) La oferta de venta del subastador holandesa Subastador -27/106- 3.3. Modelo de tareas Detalle del funcionamiento de cada rol mediante la descomposición de las tareas en secuencias de actividades y su representación en un diagrama de actividad. En este modelo se contemplan los diagramas siguientes: Figura 7. Diagrama de actividad subasta inglesa Figura 8. Diagrama de actividad subasta holandesa -28/106- 3.4. Modelo de ontologías El modelo emplea como representación gráfica un diagrama muy similar al diagrama de clases de UML para representar los conceptos de la ontología (estructura y significado de los conceptos principales del sistema) y sus relaciones. Figura 9. Diagrama de conceptos -29/106- 3.5. Modelo de coordinación Este modelo utiliza los diagramas de secuencias UML para representar las interacciones entre los roles y las etapas que las componen. En estos diagramas se muestra el flujo de mensajes, y el tipo de los mismos, entre los roles. 3.5.1. Negociación subastador inglesa y Comprador El proceso de negociación de la subasta inglesa entre subastador y comprador se coordina según protocolo de interacción FIPA English Auction Interaction Protocol [18] donde Initiator corresponde al rol de Subastador y Participant al rol de Comprador. Figura 10. Diagrama de secuencia del protocolo de interacción de la subasta inglesa 3.5.2. Negociación subastador holandesa y Comprador El proceso de negociación de la subasta holandesa entre subastador y comprador se coordina según protocolo de interacción FIPA Dutch Auction Interaction Protocol [19] donde Initiator corresponde al rol de Subastador y Participant al rol de Comprador. -30/106- Figura 11. Diagrama de secuencia del protocolo de interacción de la subasta holandesa 3.5.3. Suscripción comprador y subastador El proceso de suscripción a una subasta por parte del comprador se coordina según protocolo de interacción FIPA Subscribe Interaction Protocol [20] donde Initiator corresponde al rol de Comprador y Participant al rol de Subastador. Figura 12. Diagrama de secuencia del protocolo de suscripción mantenido entre Comprador y Subastador -31/106- 3.5.4. Búsqueda de subastas. Comprador ‐ Buscador ‐ Casa de subastas El proceso de búsqueda de una subasta por parte del comprador utilizando los servicios de un agente buscador que consulta al agente Casa de subastas se coordina según protocolo de interacción FIPA Brokering Interaction Protocol [21] donde Initiator corresponde al rol de Comprador y Broker al rol de Buscador. Figura 13. Diagrama de secuencia del protocolo FIPA-Brokering El subprotocolo utilizado para interrogar al agente Casa de subastas es el FIPA Query Interaction Protocol [22], donde Initiator es el agente Buscador y Participant es el agente Casa de subastas. -32/106- Figura 14. Diagrama de secuencia del protocolo FIPA-Query que actúa como subprotocolo en el proceso de búsqueda de una subasta -33/106- Capítulo 4. - Implementación La implementación del SMA se ha realizado en un ordenador con sistema operativo Mac OS X versión 10.5 y el entorno de desarrollo utilizado ha sido Eclipse 3.3.2. 4.1. Diagrama de clases Las clases necesarias para implementar el SMA de subastas son las que se muestran en la figura siguiente. Todas ellas incluyen comentarios tipo JavaDoc así como comentarios de línea. En el Anexo 1 se muestra el código Java de todas las clases utilizadas. Figura 15. Diagrama de clases del SMA 4.2. Implementación de los agentes Los agentes del sistema extienden una clase base llamada AgenteBase que implementa métodos de uso común para los agentes y que a su vez extiende la clase jade.core.Agent. Concretamente un método para registrar al agente en las "páginas amarillas" (DF Services) de modo que sea fácilmente localizable y otro método para quitarlo de dicho registro. Los agentes que extienden AgenteBase son: • • • • AgenteBuscador AgenteCasaSubastas AgenteComprador AgenteSubastador Los mencionados agentes implementan el rol especificado en el punto 3.1. Modelo de roles. 4.3. Comunicación entre agentes La comunicación entre los agentes se realizará acorde al Lenguaje de Comunicación de Agentes (ACL) recogido en el protocolo FIPA-ACL [23]. Un mensaje FIPA-ACL, además de los datos de emisor (sender), receptor (receiver), protocolo (protocol) y otros datos de cabecera, adjunta el tipo de acción comunicativa según se puede ver en la tabla adjunta [24]. Acción comunicativa (Performative) Significado accept‐proposal Aceptar una propuesta recibida previamente agree Estar de acuerdo en realizar alguna acción cancel Cancelar alguna acción pedida previamente cfp Solicitar propuestas para realizar una acción dada confirm Informar a un receptor que una proposición es cierta disconfirm Informar a un receptor que una proposición es falsa failure Informar a otro agente que se intentó una acción pero falló inform Informar a un receptor que una proposición es cierta inform‐if Si el agente que recibe la acción cree que la sentencia es verdadera informará de manera afirmativa, sino indicará que es falsa. inform‐ref Permite que el emisor informe al receptor de un objeto que cree que corresponde a un descriptor, como puede ser un nombre u otra descripción que lo identifique. not‐understood Informar a un receptor que el emisor no entendió el mensaje propagate El receptor trata el mensaje como si fuese dirigido directamente a él, y debe identificar -35/106- los agentes en este descriptor y enviarles el mensaje a ellos propose Enviar una propuesta para realizar una cierta acción proxy El receptor debe seleccionar agentes objetivo denotados por una descripción dada, y enviarles un mensaje embebido query‐if Preguntarle a otro agente si una determinada proposición es cierta query‐ref Preguntar a otro agente por el objeto referenciado en una expresión refuse Rechazar realizar una acción reject‐proposal Rechazar una propuesta durante una negociación request Solicitar a un receptor que realice alguna acción request‐when Solicitar al receptor que realice alguna acción cuando una proposición dada sea cierta request‐whenever Solicitar al receptor que realice alguna acción cada vez que una proposición dada sea cierta subscribe Una intención persistente de notificar al emisor de un determinado valor, y volver a notificarle cada vez que dicho valor cambie En el apartado siguiente, Implementación de los comportamientos (behaviours) se indica el tipo de acciones comunicativas que utilizarán los agentes a implementar en el sistema. 4.4. Implementación de los comportamientos (behaviours) 4.4.1. Comportamientos de subastadores Los comportamientos de los subastadores se han realizado adaptando el FIPA Contract Net Interaction Protocol [25] al protocolo de la subasta inglesa y holandesa. Encapsulan las estrategias de cada tipo de subasta: inglesa y holandesa. Las clases correspondientes a los subastadores: SubastadorHolandesaBehaviour y SubastadorInglesaBehaviour extienden la clase base SubastadorBehaviour que a su vez extiende la clase jade.proto.ContractNetInitiator. SubastadorBehaviour contiene los métodos comunes a los comportamientos de los subastadores: • • registrarTransacción. Envía un mensaje al agente CasaSubastas para que registre la transacción. getCasaSubastas. Obtiene el identificador del agente CasaSubastas registrado en las páginas amarillas. -36/106- Figura 16. FIPA Contract Net Interaction Protocol 4.4.2. Comportamientos de compradores Los comportamientos de los compradores también obedecen a una adaptación del FIPA Contract Net Interaction Protocol. Los comportamientos de los compradores encapsulan las estrategias utilizadas por los compradores y ya comentadas en el apartado 2.1.3: CompradorInglesaIncrementalBehaviour, CompradorHolandesaNRondasBehaviour y CompradorHolandesaIncrementoDinamicoBehaviour; extienden la clase jade.proto. SSIteratedContractNetResponder. 4.4.3. Comportamientos que inician una petición Estos comportamientos extienden la clase jade.proto.AchieveREInitiator que implementa los protocolos de estilo FIPA Request: • • • BuscadorBehaviourInitiator. El agente Buscador realiza al agente CasaSubastas una petición de búsqueda de una subasta en base al nombre del objeto subastado. CompradorSuscribirBehaviourInitiator. El agente Comprador realiza una petición de suscripción a un comprador para que le suscriba en una subasta. SubastadorTransaccionesBehaviourInitiator. El agente Subastador realiza una petición al agente CasaSubastas para que registre una transacción. -37/106- 4.4.4. Comportamientos que responden a una petición Estos comportamientos extienden la clase jade.proto.AchieveREResponder: • • • • BuscadorBehaviourResponder. Devuelve al agente Comprador el resultado de la búsqueda de la subasta. CasaSubastasBusquedasBehaviourResponder. Devuelve al agente Buscador el resultado de la búsqueda de la subasta. SubastadorSuscribirBehaviourResponder. Suscribe al agente Comprador a la subasta indicada en la petición correspondiente del comprador. CasaSubastasTransaccionesBehaviourResponder. Registra la transacción contenida en la petición realizada por el agente Subastador. 4.5. Implementación de las estrategias 4.5.1. Interfaces utilizados en las estrategias Se define el interface ICfgApuesta que deben implementar las estrategias de los compradores e ICfgSubasta para las estrategias de los subastadores. 4.5.2. Clases que implementan el interface ICfgApuesta Encapsulan los datos necesarios para la estrategia de los compradores. Son las siguientes, ya comentadas en el apartado 2.1.3: • • • IncrementalCfgImpl ApuestaUnicaNRondasCfgImpl ApuestaUnicaIncrementoDinamicoCfgImpl 4.5.3. Clases que implementan el interface ICfgSubasta Encapsulan los datos necesarios para la estrategia de los subastadores. Son las siguientes: • • SubastaHolandesaImpl SubastaInglesaImpl 4.6. Clases de información manejada en la subasta Se utilizan las clases Subasta que contiene todos los datos necesarios para realizar la subasta y la clase Transacción que se utilizará para el registro del historial de transacciones. -38/106- 4.7. Estructura de paquetes Las clases implementadas se estructuran dentro del paquete uoc.sma. En la figura siguiente puede verse la estructura de paquetes utilizada con el fin de organizar todas las clases del sistema según sean de tipo agente, comportamiento, etc.. Figura 17. Estructura de paquetes utilizada en el desarrollo del SMA -39/106- 4.8. Librerías utilizadas Las librería utilizadas en la implementación corresponden a: • • El Java Runtime Environment 1.5.0 El entorno de ejecución JADE 3.6.1: o http.jar o iiop.jar o jade.jar o jadeTools.jar o commons-codec-1.3.jar 4.9. Distribución final La distribución de la aplicación está almacenada en una carpeta llamada SUBASTAS dentro de la cual se encuentran las carpetas siguientes: • Carpeta src: contiene los paquetes y clases creadas en el proyecto. • Carpeta bin: contiene todas las clases del SMA en el archivo smasubastas.jar (incluyendo archivos fuente) así como las librerías de JADE. • Carpeta doc: contiene el JAVADOC de la aplicación. -40/106- Capítulo 5. - Ejecución 5.1. Ejecución del SMA La ejecución del SMA se realiza desde la clase IniciarSMA empaquetada en el archivo el archivo smasubastas.jar junto con el resto de clases del sistema multiagente. Esta clase realiza las acciones siguientes: • • • Obtiene una referencia al entorno de ejecución de JADE Crea un contenedor JADE Crea un agente de tipo AgenteCasaSubastas Para ejecutar el SMA desde la línea de comandos hay que abrir la carpeta SUBASTAS\BIN y poner el comando: java -jar smasubastas.jar Hay que tener en cuenta que las clases utilizadas se han compilado con la versión 1.5 de Java. 5.2. Test de ejecución Puesto que el sistema de subastas se ocupa de la capa de negocio y no dispone de interfaz de usuario, en la clase AgenteCasaSubastas se han implementado métodos para probar el funcionamiento del SMA. Estos métodos ya se ejecutan directamente al iniciar la aplicación. • • • testSubastas. Se lanza al crearse el AgenteCasaSubastas (método setup). Crea 2 subastas (y por tanto 2 agentes compradores), las añade al sistema e invoca la ejecución de los métodos que crean agentes compradores para la subasta inglesa y para la subasta holandesa. La primera subasta comienza transcurrido 1 minuto desde la ejecución de la clase IniciarSMA. La segunda subasta comienza 2 minutos después. testCrearCompradoresInglesa. Crea 3 agentes compradores y los suscribe a una subasta inglesa. testCrearCompradoresHolandesa. Crea 3 agentes compradores y los suscribe a una subasta holandesa. Por otra parte, para comprobar el comportamiento del agente Buscador, el agente Comprador, al iniciarse (método setup), solicita la búsqueda de una subasta al agente Buscador. La realización de otros test podría realizarse solo con modificar la clase AgenteCasaSubastas en lo que atañe a los tres métodos citados anterioemente. -41/106- El resultado de la ejecución del test es el siguiente: imac‐de‐rodolfo‐de‐benito:bin rodolfo$ java ‐jar smasubastas.jar 16‐jun‐2009 16:27:42 jade.core.Runtime beginContainer INFO: ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ This is JADE snapshot ‐ revision $WCREV$ of $WCDATE$ downloaded in Open Source, under LGPL restrictions, at http://jade.tilab.com/ ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 16‐jun‐2009 16:27:43 jade.core.BaseService init INFO: Service jade.core.management.AgentManagement initialized 16‐jun‐2009 16:27:43 jade.core.BaseService init INFO: Service jade.core.messaging.Messaging initialized 16‐jun‐2009 16:27:43 jade.core.BaseService init INFO: Service jade.core.mobility.AgentMobility initialized 16‐jun‐2009 16:27:43 jade.core.BaseService init INFO: Service jade.core.event.Notification initialized 16‐jun‐2009 16:27:43 jade.core.messaging.MessagingService clearCachedSlice INFO: Clearing cache 16‐jun‐2009 16:27:43 jade.mtp.http.HTTPServer <init> INFO: HTTP‐MTP Using XML parser com.sun.org.apache.xerces.internal.parsers.SAXParser 16‐jun‐2009 16:27:43 jade.core.messaging.MessagingService boot INFO: MTP addresses: http://192.168.0.195:7778/acc 16‐jun‐2009 16:27:43 jade.core.AgentContainerImpl joinPlatform INFO: ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ Agent container Main‐Container@imac‐de‐rodolfo‐de‐benito.local is ready. ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteCasaSubastas testSubastas INFO: El agente de casa de subastas crea el agente Buscador 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:27:43 uoc.sma.agentes.AgenteComprador$1 action INFO: Agente buscador: subasta localizada Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:28:43 uoc.sma.agentes.AgenteSubastador$1 onWake INFO: Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE ‐ Se inicia la subasta Subasta Id:1 iMac 25 Precio:2.25 Inicio:Tue Jun 16 16:28:43 CEST 2009 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador2 : ENVIA : PROPOSE : 5.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador3 : ENVIA : PROPOSE : 30.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador1 : ENVIA : PROPOSE : 25.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 30.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador1 : ENVIA : PROPOSE : 35.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador2 : ENVIA : PROPOSE : 40.0 prepareResultNotification() method not re‐defined prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 40.0 prepareResultNotification() method not re‐defined -42/106- prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador1 : ENVIA : PROPOSE : 45.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador3 : ENVIA : PROPOSE : 90.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 90.0 prepareResultNotification() method not re‐defined prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador1 : ENVIA : PROPOSE : 95.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador2 : ENVIA : PROPOSE : 160.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 160.0 prepareResultNotification() method not re‐defined prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour handleCfp INFO: Comprador1 : ENVIA : PROPOSE : 165.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 165.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Puja más alta en esta ronda: 0.0 16‐jun‐2009 16:28:43 uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour handleAllResponses INFO: Ganador de la subasta:Subasta Id:1 iMac 25 Precio:165.0 Inicio:Tue Jun 16 16:28:43 CEST 2009 el comprador Comprador1 con una puja de 165.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.agentes.AgenteSubastador$1 onWake INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE ‐ Se inicia la subasta Subasta Id:2 Mac Book pro Precio:250.0 Inicio:Tue Jun 16 16:29:43 CEST 2009 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour onEnd INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE: Oferta de venta:235.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour onEnd INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE: Oferta de venta:220.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour onEnd INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE: Oferta de venta:205.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour onEnd INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE: Oferta de venta:190.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour onEnd INFO: Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE: Oferta de venta:175.0 prepareResultNotification() method not re‐defined 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour handleAllResponses INFO: FIN DE SUBASTA 16‐jun‐2009 16:29:43 uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour handleAllResponses INFO: Ganador de la subasta:Subasta Id:2 Mac Book pro Precio:175.0 Inicio:Tue Jun 16 16:29:43 CEST 2009 el comprador Comprador6 con una puja de 175.0 -43/106- 5.2.1. Muestra de flujo de mensajes en el test de la subasta inglesa Figura 18. Intercambio de mensajes en subasta inglesa -44/106- 5.2.2. Muestra de intercambio de mensajes de negociación entre subastador y compradores en el test de la subasta inglesa Este extracto de los mensajes intercambiados entre el Subastador1 y los agentes Comprador1, Comprador2 y Comprador 3 corresponde a la primera ronda de la subasta. Se han marcado en negrita el tipo de mensaje e identificado el remitente y destinatario de los mensajes. Se puede ver que hay 3 mensajes de propuesta CFP (Call For Proposal) que el subastador dirige a los compradores con el precio de salida del artículo, 2.25 euros. También se ven los mensajes de respuesta a dichas propuestas (PROPOSE) con la puja propuesta por Comprador1, Comprador2 y Comprador3: 25.0, 5.0 y 30.0, respectivamente. (CFP :sender ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "2.25" :reply‐with R1245001470219_0 :reply‐by 20090614T174440206Z :conversation‐id C8941849_1245001470219 ) (CFP :sender ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "2.25" :reply‐with R1245001470220_1 :reply‐by 20090614T174440206Z :conversation‐id C8941849_1245001470219 ) (PROPOSE :sender ( agent‐identifier :name Comprador1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "25.0" :reply‐with "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470230" :in‐reply‐to R1245001470220_1 :conversation‐id C8941849_1245001470219 ) (CFP :sender ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador3@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "2.25" :reply‐with R1245001470222_2 :reply‐by 20090614T174440206Z :conversation‐id C8941849_1245001470219 ) (PROPOSE :sender ( agent‐identifier :name Comprador2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "5.0" :reply‐with "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470233" :in‐reply‐to R1245001470219_0 :conversation‐id C8941849_1245001470219 ) (PROPOSE -45/106- :sender ( agent‐identifier :name Comprador3@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "30.0" :reply‐with "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470248" :in‐reply‐to R1245001470222_2 :conversation‐id C8941849_1245001470219 ) 5.2.3. Muestra de flujo de mensajes en el test de la subasta holandesa Figura 19. Intercambio de mensajes en subasta holandesa -46/106- 5.2.4. Muestra de intercambio de mensajes de negociación entre subastador y compradores en el test de la subasta holandesa Este extracto de los mensajes intercambiados en la primera ronda de la subasta entre el Subastador2 y los agentes Comprador4, Comprador5 y Comprador 6 corresponde a la primera ronda de la subasta. Se pueden ver los mensajes CFP que envía el subastador a los compradores proponiendo un precio de venta de 250.0. Como contestación a este mensaje todos los compradores rechazan (CFP :sender ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador4@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "250.0" :reply‐with R1245004074545_0 :reply‐by 20090614T182804535Z :conversation‐id C476737_1245004074545 ) (CFP :sender ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador5@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "250.0" :reply‐with R1245004074546_1 :reply‐by 20090614T182804535Z :conversation‐id C476737_1245004074545 ) (REFUSE :sender ( agent‐identifier :name Comprador5@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :reply‐with "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245004074552" :in‐reply‐to R1245004074546_1 :conversation‐id C476737_1245004074545 ) (CFP :sender ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Comprador6@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "250.0" :reply‐with R1245004074548_2 :reply‐by 20090614T182804535Z :conversation‐id C476737_1245004074545 ) (REFUSE :sender ( agent‐identifier :name Comprador4@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :reply‐with "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245004074554" :in‐reply‐to R1245004074545_0 :conversation‐id C476737_1245004074545 ) (REFUSE :sender ( agent‐identifier :name Comprador6@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :reply‐with "Subastador 2@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245004074560" :in‐reply‐to R1245004074548_2 :conversation‐id C476737_1245004074545 ) -47/106- 5.2.5. Muestra de mensajes entre el agente Subastador, el agente DF y el agente CasaSubastas En este ejemplo el subastador pide con un mensaje REQUEST al agente DF que localice al agente CasaSubastas. El agente DF le responde con un mensaje INFORM indicando el identificador el agente CasaSubastas. El agente subastador le pide REQUEST al agente CsaSubastas que registre una transacción y este le responde que lo ha realizado (AGREE). (REQUEST :sender ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name df@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "((action ( agent‐identifier :name df@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) (search (df‐agent‐description :services (set (service‐description :type CasaDeSubastas))) (search‐ constraints :max‐results ‐1))))" :reply‐with "rw‐Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470264‐10" :language fipa‐sl0 :ontology FIPA‐ Agent‐Management :protocol fipa‐request :conversation‐id "conv‐Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470264‐10" ) (INFORM :sender ( agent‐identifier :name df@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :content "((result (action (agent‐identifier :name df@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc)) (search (df‐agent‐description :services (set (service‐description :type CasaDeSubastas))) (search‐ constraints :max‐results ‐1))) (sequence (df‐agent‐description :name (agent‐identifier :name Casa‐Subastas@imac‐de‐rodolfo‐de‐ benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc)) :services (set (service‐description :name \"Casa‐ Subastas‐Casa de subastas\" :type CasaDeSubastas))))))" :reply‐with "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470271" :in‐reply‐to "rw‐Subastador 1@imac‐de‐ rodolfo‐de‐benito.local:1099/JADE1245001470264‐10" :language fipa‐sl0 :ontology FIPA‐Agent‐Management :protocol fipa‐request :conversation‐id "conv‐Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470264‐10" ) (REQUEST :sender ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name Casa‐Subastas@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) ) :content uoc.sma.datos.Transaccion :reply‐with R1245001470278_0 :protocol fipa‐request :conversation‐id C6486835_1245001470278 ) (AGREE :sender ( agent‐identifier :name Casa‐Subastas@imac‐de‐rodolfo‐de‐benito.local:1099/JADE :addresses (sequence http://192.168.0.196:7778/acc )) :receiver (set ( agent‐identifier :name "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE" :addresses (sequence http://192.168.0.196:7778/acc )) ) :reply‐with "Subastador 1@imac‐de‐rodolfo‐de‐benito.local:1099/JADE1245001470290" :in‐reply‐to R1245001470278_0 :protocol fipa‐request :conversation‐id C6486835_1245001470278 ) -48/106- 5.2.6. Rondas y pujas obtenidas en el test de la subasta inglesa La subasta inicial subastaba un artículo con un precio de salida de 2.25. La configuración inicial de los compradores que participaron en ella es la siguiente: Comprador 1 2 3 Puja inicial Incremento 25 5 30 10 2 3 Tipo incremento Reserva puja+incremento puja*incremento puja*incremento 190 195 175 Las pujas en cada ronda han sido las siguientes: Ronda Comprador1 1 2 3 4 Comprador2 25 35 95 165 Comprador3 5 40 160 ‐ 30 90 ‐ ‐ Resulta ganador el Comprador 1 con una puja de 165. 5.2.7. Rondas y pujas obtenidas en el test de la subasta holandesa La subasta inicial subastaba un artículo con un precio de salida de 250. La configuración inicial de los compradores que participaron en ella es la siguiente: Comprador 4 5 6 Puja inicial Incremento 100 120 140 20 10 ‐ Estrategia Reserva IncrementalDinamico IncrementalDinamico NRondas Rondas 160 180 180 4 4 5 Las pujas en cada ronda han sido las siguientes: Ronda Subastador 2 Comprador4 Comprador5 Comprador6 1 2 3 4 5 235 220 205 190 175 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ 175 -49/106- 5.3. Sistema de logging En el proceso de desarrollo de la solución software se ha utilizado el sistema de log propio de JADE, la clase jade.util.Logger. Las clases inicializan el logger en nivel INFO para mostrar solo los mensajes de ese nivel: private final Logger logger = Logger.getMyLogger(this.getClass().getName()); logger.setLevel(Logger.INFO); Los mensajes de log que se utilizan utilizan dos niveles de detalle: INFO y FINE: logger.log(Logger.INFO,myAgent.getLocalName() + " : ENVIA : PROPOSE : " + puja); logger.log(Logger.FINE,myAgent.getName() + " : Recibe : ACCEPT"); Si es necesario un mayor detalle en el log para ver el comportamiento del sistema entonces puede establecerse el nivel FINE. -50/106- Capítulo 6. - Conclusiones y propuestas de mejora Los Sistemas Multiagente de negociación constituyen una alternativa muy a tener en cuenta en aquellos entornos en los que sea necesario elegir un algoritmo de negociación u estrategia dependiendo de determinadas circunstancias. En este sentido el trabajo realizado en este proyecto no solo se limita a las subastas electrónicas si no que puede servir de base para la resolución de problemas de planificación y optimización de recursos basados en el mejor "precio" o coste que puede ofrecer un agente en la resolución de una tarea concreta. Es importante señalar que el estudiante ha tenido la oportunidad de aplicar los conocimientos adquiridos en este proyecto en su ámbito profesional, proponiendo una solución basada en multiagentes de negociación para resolver un problema de planificación y optimización de recursos en un proyecto de I+D en el ámbito de bioenergía, en el que actualmente trabaja como ingeniero de software. En cuanto a las propuestas de mejora, son las siguientes: • Integrar el Sistema Multiagente en la capa de negocio de una aplicación J2EE, posibilitando que la utilización del sistema se realice vía Web con un simple navegador en lugar de hacerlo con una aplicación de escritorio o desde una solución software de movilidad. • Interfaz del usuario: aunque el alcance de este proyecto no incluía el interfaz del usuario, el interfaz del usuario facilitaría la interacción con el software. • Persistencia de datos: no contemplado en el alcance de este proyecto, utilizar una base de datos relacional es necesario para registrar las subastas y transacciones realizadas. • Cifrado de mensajes: puesto que los agentes pueden estar distribuidos y el intercambio de mensajes realizarse por redes no seguras como Internet, el cifrado del contenido de los mensajes puede aportar un nivel de seguridad básico al sistema. La implementación del cifrado puede realizarse con las clases del paquete javax.crypto utilizando, por ejemplo, el cifrado simétrico AES. -51/106- Bibliografía Aranda Corral (2006). Construcción de un sistema multiagente mediante Jade. Curso: Agentes Inteligentes. Universidad de Sevilla. Bellifemine, Caire, Trucco, Rimassa (2007). JADE PROGRAMMER’S GUIDE Bellifemine, Caire, Trucco, Rimassa (2007). JADE v3.6.1 API Botia (2005). Construcción de Agentes Software con JAVA + JADE. Seminario de Aplicación de los Agentes Software al Ocio y al turismo. Universidad Carlos III de Madrid. David Sánchez Ruenes. PROTOCOLS I ONTOLOGIES JADE 2.61. GUIA DE PROGRAMACIÓ. Universitat Rovira i Virgili Foundation for Intelligent Physical Agents (2003). FIPA ACL Message Structure Specification, disponible en Internet (http://www.fipa.org/specs/fipa00061/SC00061G.html) Ganzha, Paprzycki, Pirvanescu, Badica y Abraham (2001). Jade Based Multi-Agent ECommerce Environment: Initial Implementation. 6th Int. Symposium SYNASC04, Romania. García Olaya (2007). Diseño Software de Agentes Inteligentes Autónomos: Tema IV – Estándares para el desarrollo de SMA. Universidad Carlos III de Madrid. Imbert Paredes (2005). Una Arquitectura Cognitiva Multinivel para Agentes con Comportamiento Influido por Características Individuales y Emociones, Propias y de Otros Agentes. Tesis doctoral, Facultad de Informática. Universidad Politécnica De Madrid. Ismail Khalil (2009). Cooperative Systems - UE, disponible en Internet (http://www.tk.unilinz.ac.at/teaching/) Jennings, Sycara Y Wooldridge (1998). A Roadmap of Agent Research and Development. Autonomous Agents and Multi-Agent Systems, 1, 7–38 (1998). Kluwer Academic Publishers, Boston. Llamas Bello (2002). Protocolos de interacción entre agentes (FIPA). Sistemas Multiagente, Cursos de doctorado UVA. Rinkesh Patel (2006). A Trustworthy Agent Based Online Auction System. CIS Master Project. University of Massachusetts Dartmouth. Stan Franklin y Art Graesser (1996). Is it an Agent, or just a Program?: A Taxonomy for Autonomous Agents. Third International Workshop on Agent Theories, Architectures, and Languages, Springer-Verlag. Valladares Pernas (2004). Multi-Agent System for Online Auctions. CIS Master Project. University of Massachusetts Dartmouth. -52/106- Referencias bibliográficas [1] Moreno Ribas, Antonio. Agentes y sistemas multiagente. Módulo 2 P05/81007/00776. UOC [2] FIPA, disponible en Internet (http://www.fipa.org) [3] Wooldridgey Jennings (1995) [4] Luck M, McBurney P, Shehory O, Willmott S (2005) Agent Technology: Computing as Interaction (A Roadmap for Agent Based Computing). AgentLink. Disponible en Internet (http://www.agentlink.org/roadmap/al3rm.pdf) [5] Wooldridge, Michael (2002). An Introduction to Multiagent systems. Wiley [6] Posada, Marta y Lopez, Adolfo (2008). How to Choose the Bidding Strategy in Continuous Double Auctions: Imitation Versus Take-The-Best Heuristics. Journal of Artificial Societies and Social Simulation 11(1)6, disponible en Internet (http://jasss.soc.surrey.ac.uk/11/1/6.html). [7] Bagnall y Toft. Zero Intelligence Plus and Gjerstad-Dickhaut Agents for Sealed Bid Auctions. Diponible en Internet en (http://citeseer.ist.psu.edu/708332.html) [8] Posada, Lopez y Hernández (2004). Aprendizaje Evolutivo en la Subasta Doble Continua. Un enfoque Multiagente, disponible en Internet en (http://io.us.es/cio2004/comunicaciones/111-120.pdf) [9] IDK, disponible en Internet (http://grasia.fdi.ucm.es/main/?q=en/node/127) [10] Moreno, Velásquez, Ovalle. Una Aproximación Metodológica para la Construcción de Modelos de Simulación Basados en el Paradigma Multi-Agente. Avances en Sistemas e Informática, Vol.4 No. 2, Septiembre de 2007, disponible en Internet en (http://pisis.unalmed.edu.co/avances/archivos/ediciones/Edicion%20Avances%202007 %202/16.pdf) [11] JADE, disponible en Internet (http://jade.tilab.com) [12] Bellifemine, Caire, Greenwood (2007). Developing Multi Agent Systems with JADE. Wiley [13] Hibernate, disponible en Internet en (https://www.hibernate.org) [14] iBatis, disponible en Internet en (http://ibatis.apache.org) [15] Patel, Rinkesh (2006). A Trustworthy Agent Based Online Auction System, disponible en Internet (http://www.cis.umassd.edu/~hxu/Projects/UMD/TrustworthyAuction/TrustworthyAuction-System.ppt) [16] Fabra, Natalia (2003). Mecanismos de Subastas, disponible en Internet (http://www.eco.uc3m.es/nfabra/Docencia/Seminarios/Subastas_UMTS.pdf) [17] Juan Momparler, Mario Hidalgo. Modelos de subastas y su aplicación a los concursos, disponible en Internet (http://www.uv.es/asepuma/XIII/comunica/comunica_58.pdf) -53/106- [18] Foundation for Intelligent Physical Agents (2002). FIPA English Auction Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00031/index.html) [19] Foundation for Intelligent Physical Agents (2002). FIPA Dutch Auction Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00032/index.html) [20] Foundation for Intelligent Physical Agents (2002). FIPA Subscribe Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00035/SC00035H.html) [21] Foundation for Intelligent Physical Agents (2002). FIPA Brokering Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00033/SC00033H.pdf) [22] Foundation for Intelligent Physical Agents (2002). FIPA Query Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00027/SC00027H.pdf) [23] Foundation for Intelligent Physical Agents (2002). FIPA ACL Message Structure Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00061/SC00061G.pdf) [24] Escuela Superior de Ingeniería Informática de la Universidad de Vigo. Programación en JADE - Comunicación, disponible en Internet en (http://programacionjade.wikispaces.com/Comunicación) [25] Foundation for Intelligent Physical Agents (2002). FIPA ContractNet Interaction Protocol Specification, disponible en Internet en (http://www.fipa.org/specs/fipa00029/SC00029H.pdf) -54/106- Anexo A. Clases Java implementadas Clase AgenteBase package uoc.sma.agentes; import jade.core.Agent; import jade.domain.DFService; import jade.domain.FIPAException; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.util.Logger; /** * Clase base para loa agentes que contiene servicios comunes a todos ellos * * @author Rodolfo de Benito Arango * */ @SuppressWarnings("serial") public class AgenteBase extends Agent { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); @Override /* * Procedimiento que se ejecuta en la creación del agente */ protected void setup() { //Establece el nivel de mensajes del logger logger.setLevel(Logger.INFO); } /** * Registra a un agente en las páginas amarillas * para facilitar su localización * * @param tipoAgente El tipo de agente a registrar * @param nombre El nombre del agente * */ protected void registrarDFAgente(String tipoAgente, String nombre) { logger.log(Logger.FINE,this.getLocalName() +" registrando agente " + nombre +" en páginas amarillas"); //Crea la descripción del agente y le asigna el nombre de agente DFAgentDescription descripcionAgente = new DFAgentDescription(); descripcionAgente.setName(getAID()); //Crea la descripción del servicio y le asigna el nombre del agente y tipo ServiceDescription sd = new ServiceDescription(); sd.setType(tipoAgente); sd.setName(nombre); descripcionAgente.addServices(sd); try { //Registra el agente en las páginas amarillas DFService.register(this, descripcionAgente); } catch (FIPAException e) { e.printStackTrace(); } } -55/106- } /** * Localiza a un agente en las páginas amarillas * * @param tipo El tipo de agente a localizar * @return El array de agentes que responden al tpo de agente a localizar */ protected DFAgentDescription[] getAgentePaginasAmarillas(String tipo) { logger.log(Logger.FINE,this.getLocalName() +" localizando agente "+tipo+" en páginas amarillas"); //Crea la plantilla tipo del agente a localizar DFAgentDescription plantilla = new DFAgentDescription(); DFAgentDescription[] resultado = null; ServiceDescription sd = new ServiceDescription(); sd.setType(tipo); plantilla.addServices(sd); try { //Busca al agente en las páginas amarillas resultado = DFService.search(this, plantilla); } catch (FIPAException fe) { fe.printStackTrace(); } return resultado; } -56/106- Clase AgenteCasaSubastas package uoc.sma.agentes; import java.io.IOException; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.logging.FileHandler; import uoc.sma.behaviours.CasaSubastasBusquedasBehaviourResponder; import uoc.sma.behaviours.CasaSubastasTransaccionesBehaviourResponder; import uoc.sma.datos.Subasta; import uoc.sma.datos.Transaccion; import uoc.sma.estrategias.ApuestaUnicaIncrementoDinamicoCfgImpl; import uoc.sma.estrategias.ApuestaUnicaNRondasCfgImpl; import uoc.sma.estrategias.ICfgSubasta; import uoc.sma.estrategias.IncrementalCfgImpl; import uoc.sma.estrategias.SubastaHolandesaImpl; import uoc.sma.estrategias.SubastaInglesaImpl; import jade.core.AID; import jade.domain.DFService; import jade.domain.FIPAException; import jade.domain.FIPANames; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.util.Logger; import jade.util.leap.HashMap; import jade.wrapper.ControllerException; import jade.wrapper.PlatformController; import jade.wrapper.StaleProxyException; /** * Agente con las responsabilidades siguientes: * ‐Crear un agente subastador cuando se crea una nueva subasta * ‐Crear la subasta * ‐Obtener la lista de bienes que se subastan. Para acotar el problema se considera * que no puede haber 2 subastas activas que subasten el mismo bien. * ‐Buscar el ID de la subasta según el bien subastado * ‐Eliminar al agente subastador cuando concluye la subasta * * Comportamientos: * ‐Atender las peticiones de escritura en el historial de transacciones * ‐Atender las peticiones de búsqueda de subastas * * @author Rodolfo de Benito Arango * */ @SuppressWarnings("serial") public class AgenteCasaSubastas extends AgenteBase { private HashMap subastas; //La lista de subastas activas (id, subasta) private ArrayList<Transaccion> historialTransacciones; //El historial de transacciones private HashMap bienesSubastados; // La lista de bienes subastados (bienSubastado, idSubasta) private PlatformController contenedor; //Una referencia al contenedor de agentes private final Logger logger = Logger.getMyLogger(this.getClass().getName()); @Override /** * Al inicializar el agente realiza las operaciones siguientes: -57/106- * ‐Inicializar las listas de historial de transacciones * ‐Inicializar la lista de subastas activas * ‐Inicializar la lista de bienes subastados * ‐Añadir los comportamientos al agente * ‐Registrarse en las páginas amarillas * */ protected void setup() { super.setup(); //Habilita el logger para escribir en el fichero Historial.log try { FileHandler handler; handler = new FileHandler("Historial.log"); logger.addHandler(handler); } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } logger.setLevel(Logger.INFO); this.contenedor=getContainerController(); //Obtiene una referencia al contenedor //Inicialización de estructuras de datos inicializarEstructurasDatos(); //Registro en páginas amarillas registrarDFAgente("CasaDeSubastas",getLocalName() + "‐Casa de subastas"); addHistorialTransaccionesBehaviour(); addBusquedaSubastasBehaviour(); } //A modo de prueba añade subastas al sistema testSubastas(); /** * Añade el comportamiento que atiende a las peticiones de búsquedas * de subastas * * Sigue el protocolo FIPA_QUERY */ private void addBusquedaSubastasBehaviour() { logger.log(Logger.FINE,"Agente "+getLocalName()+" esperando peticiones de búsqueda de subastas..."); MessageTemplate template = MessageTemplate.and( MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_QUERY), MessageTemplate.MatchPerformative(ACLMessage.QUERY_REF) ); addBehaviour(new CasaSubastasBusquedasBehaviourResponder(this,template)); } /** * Añade el comportamiento que se encarga de atender las peticiones * de añadir información de la subasta al historial * * Sigue el protocolo FIPA‐REQUEST */ private void addHistorialTransaccionesBehaviour() { logger.log(Logger.FINE,"Agente "+getLocalName()+" esperando peticiones para el historial de transacciones..."); MessageTemplate protocolo = MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST); MessageTemplate performativa = MessageTemplate.MatchPerformative(ACLMessage.REQUEST); MessageTemplate plantilla = MessageTemplate.and(protocolo, performativa); -58/106- } addBehaviour(new CasaSubastasTransaccionesBehaviourResponder(this,plantilla)); /** * Inicializa las estructuras de datos necesarias para el agente */ private void inicializarEstructurasDatos() { historialTransacciones = new ArrayList<Transaccion>(); subastas = new HashMap(); bienesSubastados = new HashMap(); } /** * Agrega una transacción al historial * * @param t La transacción a agregar */ public void addTransaccion(Transaccion t){ historialTransacciones.add(t); logger.log(Logger.FINE,"Se ha añadido la transacción "+t); if (t.getOperación().equalsIgnoreCase(Transaccion.FIN)) { logger.log(Logger.FINE,"Se cierra la subasta "+t.getIdSubasta()); this.cerrarSubasta(t.getIdSubasta()); } } /** * Obtiene el historial de transacciones * * @return La lista de transacciones */ public ArrayList<Transaccion> getTransacciones(){ return historialTransacciones; } /** * Añade una nueva subasta al sistema * ‐Crea el Agente vendedor y lo asocia a la subasta * ‐Añade la subasta a la lista de subastas activas * ‐Añade el bien subastado a la lista de bienes * ‐Crea una nueva transacción de inicio de subasta y la añade al historial * * @param s ‐ La subasta a añadir * @param estrategiaSubasta La estrategia de subasta del vendedor (subasta inglesa, holandesa, etc.) */ private void addSubasta(Subasta s, ICfgSubasta estrategiaSubasta){ crearAgenteSubastador(s, estrategiaSubasta); subastas.put(s.getIdSubasta(), s); addBienSubastado(s.getObjetoSubastado(), s.getIdSubasta()); addTransaccion(new Transaccion(s.getFechaInicio(),s.getIdSubasta(),s.getAgenteSubastador().getLocalName(),"INICIO",s.getPrecio())); logger.log(Logger.FINE,"Se ha creado en el sistema la subasta "+s); } /** * Elimina la subasta de la lista de subastas activas * * @param id ‐ El identificador de la subasta a eliminar */ public void removeSubasta(int id){ subastas.remove(id); } -59/106- /** * Obtiene la subasta indicada por el identificador * * @param id El identidficador de la subasta * @return La subasta */ public Subasta getSubasta(int id){ return (Subasta) subastas.get(id); } /** * Añade un nuevo bien subastado a la lista * * Cada bien diferente se identifica en un HashMap cuyas * claves referencian a un ArrayList de subastas para permitir * colisiones en el HashMap * * @param b ‐ El bien que se subasta * @param l */ public void addBienSubastado(String b, int l){ bienesSubastados.put(b.toUpperCase(),new Integer(l)); logger.log(Logger.FINE,"Hay un nuevo bien subastado "+b+" en la subasta "+l); } /** * Elimina un bien de la lista de bienes subastados * * @param b El bien a eliminar */ public void removeBienSubastado(String b){ bienesSubastados.remove(b.toUpperCase()); } /** * Localiza la subasta que contiene el bien a buscar * Si no lo encuentra devuelve 0 * * @param bienSubastado El bien a localizar en la subasta * @return La subasta */ public Subasta getSubasta(String bienSubastado){ if (bienesSubastados!=null){ if (bienesSubastados.get(bienSubastado.toUpperCase())!=null){ return (Subasta) subastas.get((Integer) bienesSubastados.get(bienSubastado.toUpperCase())); } } return null; } /** * Devuelve toda la lista de subastas * @return */ public Iterator getAllSubastas(){ return (Iterator) this.subastas.values(); } -60/106- /** * Crea un nuevo agente subastador encargado de una subasta * * @param s La subasta que atiende el agente vendedor * @param estrategiaSubasta La estrategia que seguirá la subasta (Inglesa, Holandesa, etc) */ private void crearAgenteSubastador(Subasta s, ICfgSubasta estrategiaSubasta){ Object[] args = new Object[2]; args[0]=s; args[1]=estrategiaSubasta; try { contenedor.createNewAgent("Subastador "+s.getIdSubasta(), "uoc.sma.agentes.AgenteSubastador",args ).start(); } catch (StaleProxyException e) { e.printStackTrace(); } catch (ControllerException e) { e.printStackTrace(); } s.setAgenteSubastador(new AID("Subastador "+s.getIdSubasta(),AID.ISLOCALNAME)); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Subastador para la subasta "+s.getIdSubasta()); } /** * Elimina de la memoria el agente subastador * * @param localname El agente a eliminar */ private void eliminarAgenteSubastador(String localname){ try { contenedor.getAgent(localname).kill(); } catch (StaleProxyException e) { e.printStackTrace(); } catch (ControllerException e) { e.printStackTrace(); } } /** * Realiza las operaciones necesarias para eliminar la subasta * una vez ésta haya concluido: * ‐Quitar la subasta de la lista * ‐Quitar el bien subastado de la lista * ‐Eliminar al agente subastador responsable de la subasta * * @param idSubasta El identificador de la subasta a cerrar */ public void cerrarSubasta(int idSubasta){ removeBienSubastado(getSubasta(idSubasta).getObjetoSubastado()); eliminarAgenteSubastador(getSubasta(idSubasta).getAgenteSubastador().getLocalName()); removeSubasta(idSubasta); } @Override /** * Al finalizar el agente: * ‐ Quitar el registro de las páginas amarillas */ protected void takeDown() { super.takeDown(); try { DFService.deregister(this); } catch (FIPAException fe) { -61/106- fe.printStackTrace(); } logger.log(Logger.INFO,"Historial de transacciones:" + this.historialTransacciones); } /** * Método que comprueba el funcionamiento de las subastas inglesa y holandesa * Crea una subasta inglesa y una subasta holandesa * * Crea 3 agentes compradores para una subasta inglesa y 3 compradores para * una subasta holandesa. * * Crea un agente buscador. * */ private void testSubastas() { GregorianCalendar fInicioS1= new GregorianCalendar(); fInicioS1.add(GregorianCalendar.MINUTE, 1); Subasta s1 = new Subasta(1,fInicioS1.getTime(),"iMac 25",2.25,50,true,Subasta.SUBASTA_INGLESA); //ICfgSubasta e1 = new SubastaInglesaImpl(); GregorianCalendar fInicioS2= new GregorianCalendar(); fInicioS2.add(GregorianCalendar.MINUTE, 2); Subasta s2 = new Subasta(2,fInicioS2.getTime(),"Mac Book pro",250,0,true,Subasta.SUBASTA_HOLANDESA); //Crea 2 subasta de ejemplo addSubasta(s1,new SubastaInglesaImpl()); addSubasta(s2,new SubastaHolandesaImpl()); try { // Crea agente buscador de subastas contenedor.createNewAgent("Buscador", "uoc.sma.agentes.AgenteBuscador",null ).start(); logger.log(Logger.INFO,"El agente de casa de subastas crea el agente Buscador"); testCrearCompradoresInglesa(s1); testCrearCompradoresHolandesa(s2); } catch (StaleProxyException e) { e.printStackTrace(); } catch (ControllerException e) { e.printStackTrace(); } } /** * Crea 3 compradores de prueba para la subasta Holandesa * * @param s2 * @throws StaleProxyException * @throws ControllerException */ private void testCrearCompradoresHolandesa(Subasta s2) throws StaleProxyException, ControllerException { Object[] args4 = new Object[2]; args4[0]= s2; args4[1] =new ApuestaUnicaIncrementoDinamicoCfgImpl(20,100,160,4); Object[] args5 = new Object[2]; args5[0]= s2; args5[1] =new ApuestaUnicaIncrementoDinamicoCfgImpl(10,120,180,4); Object[] args6 = new Object[2]; args6[0]= s2; -62/106- } args6[1] =new ApuestaUnicaNRondasCfgImpl(0,140,180,5); contenedor.createNewAgent("Comprador4", "uoc.sma.agentes.AgenteComprador",args4 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador4 para la subasta "+s2.getIdSubasta()); contenedor.createNewAgent("Comprador5", "uoc.sma.agentes.AgenteComprador",args5 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador5 para la subasta "+s2.getIdSubasta()); contenedor.createNewAgent("Comprador6", "uoc.sma.agentes.AgenteComprador",args6 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador6 para la subasta "+s2.getIdSubasta()); } /** * Crea compradores de prueba para la subasta Inglesa * * @param s1 * @throws StaleProxyException * @throws ControllerException */ private void testCrearCompradoresInglesa(Subasta s1) throws StaleProxyException, ControllerException { Object[] args1 = new Object[2]; args1[0]= s1; args1[1] =new IncrementalCfgImpl(0,10,25,190); Object[] args2 = new Object[2]; args2[0]= s1; args2[1] =new IncrementalCfgImpl(1,2,5,195); Object[] args3 = new Object[2]; args3[0]= s1; args3[1] =new IncrementalCfgImpl(1,15,30,175); contenedor.createNewAgent("Comprador1", "uoc.sma.agentes.AgenteComprador",args1 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador1 para la subasta "+s1.getIdSubasta()); contenedor.createNewAgent("Comprador2", "uoc.sma.agentes.AgenteComprador",args2 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador2 para la subasta "+s1.getIdSubasta()); contenedor.createNewAgent("Comprador3", "uoc.sma.agentes.AgenteComprador",args3 ).start(); logger.log(Logger.FINE,"El agente de casa de subastas crea el agente Comprador3 para la subasta "+s1.getIdSubasta()); } -63/106- Clase AgenteSubastador package uoc.sma.agentes; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import uoc.sma.behaviours.SubastadorSuscribirBehaviourResponder; import uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour; import uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour; import uoc.sma.datos.Subasta; import uoc.sma.estrategias.ICfgSubasta; import jade.core.AID; import jade.core.behaviours.WakerBehaviour; import jade.domain.FIPAAgentManagement.FailureException; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.SubscriptionResponder; import jade.proto.SubscriptionResponder.Subscription; import jade.proto.SubscriptionResponder.SubscriptionManager; import jade.util.Logger; /** * Agente que se encarga de una subasta determinada puesta en marcha por un * usuario Tiene las responsabilidades siguientes: * ‐Aceptar las pujas de los compradores y efectuar las postcondiones a la recepción de una puja * ‐Notificar a los agentes compradores participantes los cambios de precio en * la subasta * ‐Notificar el ganador * * @author Rodolfo de Benito Arango * */ @SuppressWarnings("serial") public class AgenteSubastador extends AgenteBase { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private Subasta subasta; private ICfgSubasta estrategiaSubasta; private Set<Subscription> suscripciones = new HashSet<Subscription>(); public Subasta getSubasta() { return subasta; } public void setSubasta(Subasta subasta) { this.subasta = subasta; } public Set<Subscription> getSuscripciones() { return suscripciones; } public void setSuscripciones(Set<Subscription> suscripciones) { this.suscripciones = suscripciones; } public ICfgSubasta getEstrategiaSubasta() { return estrategiaSubasta; } -64/106- /** * Añade el comportamiento con la estrategia que utilizará el comprador * * @param estrategiaSubasta La estrategia a seguir en la compra */ public void setEstrategiaSubasta(ICfgSubasta estrategiaSubasta) { this.estrategiaSubasta = estrategiaSubasta; } @Override protected void setup() { super.setup(); // Comprueba los argumentos del agente subastador y obtiene la estrategia del vendedor subasta = (Subasta) this.getArguments()[0]; if ((getArguments()!=null) && (getArguments().length>=2)){ setEstrategiaSubasta((ICfgSubasta)getArguments()[1]); }else{ logger.log(Logger.INFO,"El agente "+this.getLocalName()+" no dispone de ninguna estrategia de venta"); //Termina la ejecución del agente cuando el número de argumentos es incorrecto this.doDelete(); } logger.log(Logger.FINE,"Agente subastador " + this.getLocalName() + " creado."); logger.log(Logger.FINE,this.getLocalName()+ ": Esperando suscripciones a la subasta..."); // Se crea una plantilla para que sólo se admitan mensajes del protocolo FIPA‐Subscribe MessageTemplate template = SubscriptionResponder.createMessageTemplate(ACLMessage.SUBSCRIBE); // Se crea un SubscriptionManager que registrará y eliminará las suscripciones. SubscriptionManager gestor = crearGestorSubscripciones(); // Se añade un comportamiento que maneja los mensajes recibidos para suscribirse. this.addBehaviour(new SubastadorSuscribirBehaviourResponder(this, template, gestor)); this.addBehaviour(new WakerBehaviour(this,subasta.getFechaInicio()) { } } ); @Override protected void onWake() { super.onWake(); logger.log(Logger.INFO,myAgent.getName() + " ‐ Se inicia la subasta "+subasta); ACLMessage cfpMsg = new ACLMessage(ACLMessage.CFP); cfpMsg.setContent(String.valueOf(subasta.getPrecio())); cfpMsg.setReplyByDate(new Date(System.currentTimeMillis() + 10000)); if (subasta.getTipoSubasta()==Subasta.SUBASTA_INGLESA) myAgent.addBehaviour(new SubastadorInglesaBehaviour(myAgent, cfpMsg)); else if (subasta.getTipoSubasta()==Subasta.SUBASTA_HOLANDESA) myAgent.addBehaviour(new SubastadorHolandesaBehaviour(myAgent, cfpMsg)); } /** * Crea el gestor de suscripciones y define los métodos para * suscribir y desuscribir agentes a las subastas * * @return */ private SubscriptionManager crearGestorSubscripciones() { SubscriptionManager gestor = new SubscriptionManager() { -65/106- public boolean deregister(Subscription suscripcion) throws FailureException { if (suscripcion.getMessage().getContent() != null) { int idSubasta = obtenerIdSubasta(suscripcion.getMessage() .getContent()); suscripciones.remove(suscripcion); return removeSuscriptor(suscripcion.getMessage() .getSender(), idSubasta); } return false; } public boolean register(Subscription suscripcion) throws RefuseException, NotUnderstoodException { if (suscripcion.getMessage().getContent() != null) { int idSubasta = obtenerIdSubasta(suscripcion.getMessage() .getContent()); suscripciones.add(suscripcion); return addSuscriptor(suscripcion.getMessage().getSender(), idSubasta); } return false; } } private int obtenerIdSubasta(String content) { return Integer.parseInt(content); } }; return gestor; @Override protected void takeDown() { super.takeDown(); } /** * Añade un suscriptor a la lista de suscriptores * * @param suscriptor */ public boolean addSuscriptor(AID suscriptor, int idSubasta){ subasta.getSuscriptores().add(suscriptor); logger.log(Logger.FINE,"Se ha añadido el suscriptor "+ suscriptor.getLocalName()+ " a la subasta "+subasta); return true; } /** * Elimina un suscriptor de la lista de suscriptores * * @param suscriptor */ public boolean removeSuscriptor(AID suscriptor, int idSubasta){ subasta.getSuscriptores().remove(suscriptor); logger.log(Logger.FINE,"Se ha eliminado el suscriptor "+ suscriptor.getLocalName()+ " de la subasta "+subasta); return true; } //Comprueba la propuesta. En este caso si el contenido del mensaje tiene una longitud mayor que 2, devuelve true public boolean compruebaMensaje(String propuesta) { return true; } -66/106- } /** * Añade al mensaje CFP a los suscriptores de la subasta * * @param m El mensaje que se enviará * @return */ public ACLMessage addAgentsToMessage(ACLMessage m) { Iterator<AID> it = subasta.getSuscriptores().iterator(); while (it.hasNext()){ m.addReceiver(it.next()); } return m; } Clase AgenteBuscador package uoc.sma.agentes; import uoc.sma.behaviours.BuscadorBehaviourInitiator; import uoc.sma.behaviours.BuscadorBehaviourResponder; import jade.domain.DFService; import jade.domain.FIPAException; import jade.domain.FIPANames; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.util.Logger; /** * Agente que tiene como responsabilidad principal localizar * las subastas activas de interés para el comprador * a partir del bien a comprar y comunicarselas al usuario. * * Se basa en FIPA‐BROKERING de tal manera que este agente buscador actua de * intermediario entre el agente CasaSubastas y el agente comprador. * El agente comprador le pide realizar una búsqueda y el agente buscador * se la remite al agente CasaSubastas. * Cuando el agente CasaSubastas devuelve el resultado de la búsqueda, * este agente retorna el resultado al comprador * * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class AgenteBuscador extends AgenteBase { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); @Override /* * Procedimiento que se ejecuta en la creación del agente */ protected void setup() { logger.log(Logger.FINE,"Agente " + getLocalName() + " esperando peticiones..."); registrarDFAgente("BUSCADOR", this.getLocalName()); //Crea una plantilla de mensajes con el protocolo FIPA_REQUEST -67/106- } //con mensajes de tipo REQUEST MessageTemplate template = MessageTemplate.and(MessageTemplate .MatchProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST), MessageTemplate.MatchPerformative(ACLMessage.REQUEST)); } // Registra un AchieveREInitiator para el estado PREPARE_RESULT_NOTIFICATION // Que se utilizará para iniciar la conversación con el agente CasaSubastas // solicitando que realice una búsqueda y para devolver el resultado de la búsqueda // al agente comprador responder.registerPrepareResultNotification(new BuscadorBehaviourInitiator(this, null)); addBehaviour(responder); //Añade al agente el comportamiento que responderá a las peticiones del agente Comprador BuscadorBehaviourResponder responder = new BuscadorBehaviourResponder(this,template); @Override /* * Se ejecuta al finalizar el agente */ protected void takeDown() { super.takeDown(); //Elimina la entrada de las páginas amarillas try { DFService.deregister(this); } catch (FIPAException fe) { fe.printStackTrace(); } } Clase AgenteComprador package uoc.sma.agentes; import uoc.sma.behaviours.CompradorSuscribirBehaviourInitiator; import uoc.sma.behaviours.estrategias.CompradorHolandesaIncrementoDinamicoBehaviour; import uoc.sma.behaviours.estrategias.CompradorHolandesaNRondasBehaviour; import uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour; import uoc.sma.datos.Subasta; import uoc.sma.estrategias.ApuestaUnicaIncrementoDinamicoCfgImpl; import uoc.sma.estrategias.ApuestaUnicaNRondasCfgImpl; import uoc.sma.estrategias.ICfgApuesta; import uoc.sma.estrategias.IncrementalCfgImpl; import jade.core.AID; import jade.core.behaviours.Behaviour; import jade.domain.FIPANames; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.lang.acl.UnreadableException; import jade.util.Logger; /** * Agente responsable de: * ‐Pujar en una subasta acorde a unos parámetros fijados por el usuario * ‐Admite varias estrategias: * Incremental: partiendo de un precio mínimo y uno máximo, el agente realiza pujas -68/106- * a un intervalo de tiempos fijado por el usuario incrementando la puja en * una cantidad fija estipulada por el usuario. * Francotirador: parte de un precio máximo al que está dispuesto a llegar el comprador * (precio de reserva) y realiza un puja en el último minuto de la subasta * por una importe comprendido entre la puja máxima en ese momento y el * precio de reserva del comprador. * Primerapuja: el agente hace una puja instantanea por el importe señalado por el comprador. * * El sistema está abierto a implementar cualquier otra estrategia sin que esto implique * cambio alguno en la arquitectura del SMA. * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class AgenteComprador extends AgenteBase { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private Subasta subasta; // Contiene una referencia a la subasta a la que se suscribirá el comprador private ICfgApuesta estrategia; private AID idBuscador=null; public ICfgApuesta getEstrategia() { return estrategia; } public void setEstrategia(ICfgApuesta estrategiaComprador) { this.estrategia = estrategiaComprador; } public Subasta getSubasta() { return subasta; } public void setSubasta(Subasta subasta) { this.subasta = subasta; } @Override protected void setup() { logger.setLevel(Logger.INFO); //Comprueba que el número de argumentos pasados en la creación del agente sean correctos if ((getArguments()!=null) && (getArguments().length>=2)){ setEstrategia((ICfgApuesta)getArguments()[1]); }else{ logger.log(Logger.FINE,"El agente "+this.getLocalName()+" no dispone de ninguna estrategia"); this.doDelete(); } // Localiza al Agente Buscador en las páginas amarillas DFAgentDescription[] aBuscador = getAgentePaginasAmarillas("BUSCADOR"); if (aBuscador != null) this.idBuscador = aBuscador[0].getName(); addSuscripcionBehaviour(); addEstrategiaBehaviour(); addBusquedaBehaviour(); testAgenteBuscador("iMac 25"); } -69/106- /** * Método de prueba que utiliza al aagente buscador para localizar subastas * activas que contenga el texto pasado como parámetro * * @param cadenaBusqueda */ private void testAgenteBuscador(String cadenaBusqueda) { if (idBuscador!=null){ logger.log(Logger.FINE,this.getLocalName() +" verificando el funcionamiento del agente buscador"); ACLMessage mensaje = new ACLMessage(ACLMessage.REQUEST); mensaje.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST); mensaje.setContent(cadenaBusqueda); mensaje.addReceiver(idBuscador); this.send(mensaje); }else logger.log(Logger.INFO,this.getLocalName() +" no se pudo localizar al agente buscador en páginas amarillas"); } /** * Añade como comportamiento una clase interna que, a su vez, añadirá como comportamiento * la recepción de un mensaje de tipo INFORM procedente del agente buscador */ private void addBusquedaBehaviour() { addBehaviour(new Behaviour(){ //Plantilla para responder a los mensajes tipo INFORM procedentes del agente buscador MessageTemplate template = MessageTemplate.and(MessageTemplate .MatchProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST), MessageTemplate.MatchPerformative(ACLMessage.INFORM)); public void action() { //Espera un mensaje tipo INFORM ACLMessage mensaje = receive(template); if (mensaje != null) { try { if (mensaje.getContentObject()!=null){ //Muestra la subasta buscada logger.log(Logger.INFO,"Agente buscador: subasta localizada "+(Subasta) mensaje.getContentObject()); }else logger.log(Logger.INFO," El agente buscador no ha localizado ninguna subasta"); } catch (UnreadableException e) { e.printStackTrace(); } }else { block(); } } @Override public boolean done() { return false; } }); } -70/106- /** * Añade como comportamiento una clase interna que, a su vez, añadirá como comportamiento * la estrategia que corresponda al recibir un mensaje de tipo CFP (simboliza el inicio de la subasta) */ private void addEstrategiaBehaviour() { addBehaviour(new Behaviour(){ //Plantilla para responder a los mensajes tipo CFP private MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP); public void action() { //Espera un mensaje tipo CFP ACLMessage cfp = receive(mt); if (cfp != null) { //Cuando recibe el mensaje añade el comportamiento que coresponde a la estrategia de compra logger.log(Logger.FINE,myAgent.getLocalName() + " : RECIBE : CFP"); if (estrategia instanceof ApuestaUnicaIncrementoDinamicoCfgImpl) { myAgent.addBehaviour(new CompradorHolandesaIncrementoDinamicoBehaviour(myAgent,cfp)); } if (estrategia instanceof ApuestaUnicaNRondasCfgImpl) { myAgent.addBehaviour(new CompradorHolandesaNRondasBehaviour(myAgent,cfp)); } if (estrategia instanceof IncrementalCfgImpl) { myAgent.addBehaviour(new CompradorInglesaIncrementalBehaviour(myAgent,cfp)); } }else { block(); } } @Override public boolean done() { return false; } }); } /** * Añade el comportamiento para que el comprador pueda suscribirse a una subasta * cuyo ID se pasa como parámetro en la creación del agente * * Sigue el protocolo FIPA‐Subscribe */ private void addSuscripcionBehaviour(){ //Se crea un mensaje de tipo SUBSCRIBE y se asocia al protocolo FIPA‐Subscribe. ACLMessage mensaje = new ACLMessage(ACLMessage.SUBSCRIBE); mensaje.setProtocol(FIPANames.InteractionProtocol.FIPA_SUBSCRIBE); //Trabaja con el primero de los argumentos de creación del agente //para obtener el identificador de la subasta al que va a suscribirse //el agente comprador if (getArguments()!=null){ setSubasta((Subasta)getArguments()[0]); int idSubasta = subasta.getIdSubasta(); //Pasa en el mensaje el identificador de la subasta a la que debe suscribirse mensaje.setContent(String.valueOf(idSubasta)); //La subasta a la que se suscribe //Añade el comportamiento this.addBehaviour(new CompradorSuscribirBehaviourInitiator(this, mensaje)); }else{ logger.log(Logger.FINE,"El agente "+this.getLocalName()+" no dispone de ninguna subasta a la que suscribirse"); } } } -71/106- Clase SubastadorBehaviour package uoc.sma.behaviours.estrategias; import java.io.IOException; import uoc.sma.behaviours.SubastadorTransaccionesBehaviourInitiator; import uoc.sma.datos.Transaccion; import jade.core.AID; import jade.core.Agent; import jade.domain.DFService; import jade.domain.FIPAException; import jade.domain.FIPANames; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.lang.acl.ACLMessage; import jade.proto.ContractNetInitiator; @SuppressWarnings("serial") public class SubastadorBehaviour extends ContractNetInitiator { public SubastadorBehaviour(Agent a, ACLMessage cfp) { super(a, cfp); } /** * Envía un mensaje al agente CasaSubastas para que registre la transacción * * @param t * La transacción * @param idCasaSubastas * El identificador del agente CasaSubastas */ protected void registrarTransaccion(Transaccion t, AID idCasaSubastas) { ACLMessage msg = new ACLMessage(ACLMessage.REQUEST); msg.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST); msg.addReceiver(idCasaSubastas); try { msg.setContentObject(t); } catch (IOException e) { e.printStackTrace(); } myAgent.addBehaviour(new SubastadorTransaccionesBehaviourInitiator(myAgent, msg)); } /** * Obtiene el identificador del agente CasaSubastas de las páginas amarillas * @return */ protected DFAgentDescription[] getCasaSubastas() { DFAgentDescription template = new DFAgentDescription(); DFAgentDescription[] result = null; ServiceDescription sd = new ServiceDescription(); sd.setType("CasaDeSubastas"); template.addServices(sd); try { result = DFService.search(myAgent, template); } catch (FIPAException fe) { fe.printStackTrace(); } return result; } } -72/106- Clase SubastadorHolandesaBehaviour package uoc.sma.behaviours.estrategias; import java.util.Date; import java.util.Vector; import uoc.sma.agentes.AgenteSubastador; import uoc.sma.datos.Subasta; import uoc.sma.datos.Transaccion; import uoc.sma.estrategias.SubastaHolandesaImpl; import jade.core.AID; import jade.core.Agent; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.lang.acl.ACLMessage; import jade.util.Logger; /** * Encapsula el comportamiento de un agente subastador de subasta Holandesa * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class SubastadorHolandesaBehaviour extends SubastadorBehaviour { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AgenteSubastador agente; private Subasta s; private SubastaHolandesaImpl estrategiaVendedor; private AID idCasaSubastas; private double decremento = 15; // El decremento de precio que se aplicará // en cada ronda private int contadorPujas = 0; private boolean finalSubasta = false; private boolean inferiorReserva = false; public SubastadorHolandesaBehaviour(Agent a, ACLMessage msg) { super(a, msg); logger.setLevel(Logger.INFO); agente = (AgenteSubastador) myAgent; s = agente.getSubasta(); estrategiaVendedor = (SubastaHolandesaImpl) agente .getEstrategiaSubasta(); // Localizar al Agente de Subastas en las páginas amarillas DFAgentDescription[] aCasaSubastas = getCasaSubastas(); if (aCasaSubastas != null) this.idCasaSubastas = aCasaSubastas[0].getName(); } @Override /** * Prepara el mensaje CFP siguiente */ protected Vector prepareCfps(ACLMessage cfp) { cfp = agente.addAgentsToMessage(cfp); Vector mensajes = new Vector(); mensajes.add(cfp); -73/106- } return mensajes; @Override /** * Comprueba si es necesaria otra ronda y la inicia si es preciso */ public int onEnd() { if (finalSubasta == false) { ACLMessage nextMsg = new ACLMessage(ACLMessage.CFP); nextMsg.setContent(String.valueOf(s.getPrecio())); logger.log(Logger.INFO, myAgent.getName() + ": Oferta de venta:" + s.getPrecio()); myAgent.addBehaviour(new SubastadorHolandesaBehaviour(myAgent, nextMsg)); } } return super.onEnd(); /** * Gestiona las respuestas de todos los participantes en la subasta */ protected void handleAllResponses(Vector respuestas, Vector acceptances) { contadorPujas = 0; for (ACLMessage respuesta : (Vector<ACLMessage>) respuestas) { // Controlar los mensajes de tipo REFUSE (el agente no puja) if (respuesta.getPerformative() == ACLMessage.REFUSE) { logger.log(Logger.FINE, respuesta.getSender().getLocalName() + " NO PUJA"); } // Hay una puja if (contadorPujas > 0) { finalSubasta = true; logger.log(Logger.INFO, "FIN DE SUBASTA"); // Controla los mensajes de tipo PROPOSE (las pujas) } else if (respuesta.getPerformative() == ACLMessage.PROPOSE) { ++contadorPujas; double puja = Double.parseDouble(respuesta.getContent()); logger.log(Logger.FINE, "Agente:" + respuesta.getSender().getLocalName() + " Puja=" + String.valueOf(puja)); registrarTransaccion(new Transaccion(new Date(), s .getIdSubasta(), respuesta.getSender().getLocalName(), Transaccion.PUJA, puja), idCasaSubastas); // Puja ganadora s.setPrecio(puja); s.setMsgMejorOferta(respuesta); break; } // Enviar ACCEPT si hay un ganador if (s.getMsgMejorOferta() != null) { // Establece el ganador de la subasta s.setGanador(s.getMsgMejorOferta().getSender()); logger.log(Logger.INFO, "Ganador de la subasta:" + s + " el comprador " + s.getMsgMejorOferta().getSender().getLocalName() + " con una puja de " + s.getPrecio()); registrarTransaccion(new Transaccion(new Date(), s .getIdSubasta(), s.getMsgMejorOferta().getSender() .getLocalName(), Transaccion.FIN, s.getPrecio()), idCasaSubastas); -74/106- ACLMessage accept = s.getMsgMejorOferta().createReply(); accept.setPerformative(ACLMessage.ACCEPT_PROPOSAL); accept.setContent(String.valueOf(s.getPrecio())); acceptances.add(accept); } else { } for (ACLMessage response : (Vector<ACLMessage>) respuestas) { if (s.getMsgMejorOferta() != response) { ACLMessage reject = response.createReply(); reject.setPerformative(ACLMessage.REJECT_PROPOSAL); reject.setContent(String.valueOf(s.getPrecio())); acceptances.add(reject); } } } } // En caso que no se reciba ninguna respuesta o el nuevo precio sea // inferior al de reserva // se da por finalizada la subasta sin ganador if (respuestas.size() == 0 || inferiorReserva) { logger.log( Logger.INFO,"No hay ganador de la subasta. Se ha agotado el tiempo máximo de espera de nuevas pujas o el vendedor no bajará mas el precio"); for (ACLMessage response : (Vector<ACLMessage>) respuestas) { ACLMessage reject = response.createReply(); reject.setPerformative(ACLMessage.REJECT_PROPOSAL); reject.setContent(String.valueOf(s.getPrecioReserva())); acceptances.add(reject); finalSubasta = true; } } // Recalcular la nueva oferta de precio por parte del vendedor double nuevoPrecio = s.getPrecio() ‐ decremento; if (nuevoPrecio >= s.getPrecioReserva()) { s.setPrecio(nuevoPrecio); registrarTransaccion(new Transaccion(new Date(), s .getIdSubasta(), myAgent.getLocalName(), Transaccion.OFERTA, s.getPrecio()), idCasaSubastas); } else inferiorReserva = true; -75/106- Clase SubastadorInglesaBehaviour package uoc.sma.behaviours.estrategias; import java.util.Date; import java.util.Vector; import uoc.sma.agentes.AgenteSubastador; import uoc.sma.datos.Subasta; import uoc.sma.datos.Transaccion; import uoc.sma.estrategias.SubastaInglesaImpl; import jade.core.AID; import jade.core.Agent; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.lang.acl.ACLMessage; import jade.util.Logger; /** * Encapsula el comportamiento de un agente subastador de subasta inglesa * * @author Rodolfo de Benito * */ public class SubastadorInglesaBehaviour extends SubastadorBehaviour { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AgenteSubastador agente; private Subasta s; private SubastaInglesaImpl estrategiaVendedor; private AID idCasaSubastas; private int contadorPujas = 0; private boolean finalSubasta = false; public SubastadorInglesaBehaviour(Agent a, ACLMessage msg) { super(a, msg); agente = (AgenteSubastador) myAgent; s = agente.getSubasta(); estrategiaVendedor = (SubastaInglesaImpl) agente.getEstrategiaSubasta(); // Localizar al Agente de Subastas en las páginas amarillas DFAgentDescription[] aCasaSubastas = getCasaSubastas(); if (aCasaSubastas != null) this.idCasaSubastas = aCasaSubastas[0].getName(); } @Override /** * Prepara el mensaje CFP siguiente */ protected Vector prepareCfps(ACLMessage cfp) { cfp = agente.addAgentsToMessage(cfp); Vector mensajes = new Vector(); mensajes.add(cfp); return mensajes; } -76/106- @Override /** * Comprueba si es necesaria otra ronda y la inicia si es preciso */ public int onEnd() { if (finalSubasta == false) { ACLMessage nextMsg = new ACLMessage(ACLMessage.CFP); nextMsg.setContent(String.valueOf(s.getPrecio())); myAgent.addBehaviour(new SubastadorInglesaBehaviour(myAgent, nextMsg)); } return super.onEnd(); } /** * Gestiona las respuestas de todos los participantes en la subasta */ protected void handleAllResponses(Vector respuestas, Vector acceptances) { ACLMessage mejorOfertaMsg = null; double mejorPuja = 0; contadorPujas = 0; for (ACLMessage respuesta : (Vector<ACLMessage>) respuestas) { // Controlar los mensajes de tipo REFUSE (el agente no puja) if (respuesta.getPerformative() == ACLMessage.REFUSE) { logger.log(Logger.FINE, respuesta.getSender().getLocalName() + " NO PUJA"); // Controla los mensajes de tipo PROPOSE (las pujas) } else if (respuesta.getPerformative() == ACLMessage.PROPOSE) { ++contadorPujas; double puja = Double.parseDouble(respuesta.getContent()); logger.log(Logger.FINE, "Agente:" + respuesta.getSender().getLocalName() + " Puja=" + String.valueOf(puja)); registrarTransaccion(new Transaccion(new Date(), s .getIdSubasta(), respuesta.getSender().getLocalName(), Transaccion.PUJA, puja), idCasaSubastas); } } logger.log(Logger.INFO, "Puja más alta en esta ronda: " + String.valueOf(mejorPuja)); if (contadorPujas == 0) { finalSubasta = true; logger.log(Logger.FINE, "No hay más pujas"); // Comprueba si es la mejor puja if (puja > mejorPuja) { mejorPuja = puja; s.setPrecio(mejorPuja); mejorOfertaMsg = respuesta; s.setMsgMejorOferta(mejorOfertaMsg); } // Enviar ACCEPT si hay un ganador if ((s.getMsgMejorOferta()) != null && (s.getPrecio() > s.getPrecioReserva())) { // Establece el ganador de la subasta s.setGanador(s.getMsgMejorOferta().getSender()); logger.log(Logger.INFO, "Ganador de la subasta:" + s + " el comprador " + s.getMsgMejorOferta().getSender().getLocalName() + " con una puja de " + s.getPrecio()); -77/106- } registrarTransaccion(new Transaccion(new Date(), s .getIdSubasta(), s.getMsgMejorOferta().getSender() .getLocalName(), Transaccion.FIN, s.getPrecio()), idCasaSubastas); ACLMessage accept = s.getMsgMejorOferta().createReply(); accept.setPerformative(ACLMessage.ACCEPT_PROPOSAL); accept.setContent(String.valueOf(s.getPrecio())); acceptances.add(accept); } else { for (ACLMessage response : (Vector<ACLMessage>) respuestas) { if (s.getMsgMejorOferta() != response) { ACLMessage reject = response.createReply(); reject.setPerformative(ACLMessage.REJECT_PROPOSAL); reject.setContent(String.valueOf(s.getPrecio())); acceptances.add(reject); } } } } } } logger.log(Logger.INFO, "No hay ganador de la subasta. Las pujas no superan el precio de reserva: " + s.getPrecioReserva()); for (ACLMessage response : (Vector<ACLMessage>) respuestas) { ACLMessage reject = response.createReply(); reject.setPerformative(ACLMessage.REJECT_PROPOSAL); reject.setContent(String.valueOf(s.getPrecioReserva())); acceptances.add(reject); -78/106- Clase CompradorInglesaIncrementalBehaviour package uoc.sma.behaviours.estrategias; import uoc.sma.agentes.AgenteComprador; import uoc.sma.estrategias.IncrementalCfgImpl; import jade.core.Agent; import jade.domain.FIPAAgentManagement.FailureException; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.proto.SSIteratedContractNetResponder; import jade.util.Logger; /** * Estrategia del comprador de la subasta inglesa en la que el agente puja a * intervalos regulares incrementando la puja en una cantidad preestablecida al * crear el agente. Se puede optar por una de estas dos formas de incrementar la * puja: * * Nueva puja = puja anterior + incremento. Nueva puja = puja anterior * * incremento. * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class CompradorInglesaIncrementalBehaviour extends SSIteratedContractNetResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AgenteComprador agente; private IncrementalCfgImpl estrategia; private double puja = 0; private int contadorPujas = 0; public CompradorInglesaIncrementalBehaviour(Agent a, ACLMessage cfp) { super(a, cfp); logger.setLevel(Logger.INFO); agente = (AgenteComprador) a; estrategia = (IncrementalCfgImpl) agente.getEstrategia(); } @Override /** * Trata los mensajes Call For Proposal procedentes del comprador con la * puja actual de la subasta * * En este método decide si pujar o no y el importe de la puja, enviando un * mensaje de propuesta (si puja) o de rechazo (si no puja) * */ protected ACLMessage handleCfp(ACLMessage cfp) throws RefuseException, FailureException, NotUnderstoodException { ACLMessage firstPropose = cfp.createReply(); puja = obtenerPuja(Double.parseDouble(cfp.getContent())); if ((pujaAceptable(puja)) && (puja > Double.parseDouble(cfp.getContent()))) { // La puja no sobrepasa el precio de reserva del comprador -79/106- } // y además es mayor que la puja actual. Se propone una puja firstPropose.setPerformative(ACLMessage.PROPOSE); logger.log(Logger.INFO, myAgent.getLocalName() + " : ENVIA : PROPOSE : " + puja); firstPropose.setContent(String.valueOf(puja)); estrategia.setPuja(puja); ++contadorPujas; } else { // No puja firstPropose.setPerformative(ACLMessage.REFUSE); logger.log(Logger.FINE, myAgent.getLocalName() + " : ENVIA : REFUSE : " + cfp.getContent()); } return firstPropose; @Override protected void handleRejectProposal(ACLMessage cfp, ACLMessage propose, ACLMessage reject) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Recibe : REJECT"); } if (reject == null) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Responder : TIMEOUT"); } @Override /** * Trata los mensajes de aceptación de propuesta de puja procedentes del * subastador En caso de recibir un mensaje de aceptación indica que la puja * del agente es la ganadora de la subasta y se envía un mensaje INFORM al * agente subastador confirmando en importe de la puja ganadora */ protected ACLMessage handleAcceptProposal(ACLMessage cfp, ACLMessage propose, ACLMessage accept) throws FailureException { logger.log(Logger.FINE, myAgent.getName() + " : Recibe : ACCEPT"); if (accept != null) { ACLMessage inform = accept.createReply(); inform.setPerformative(ACLMessage.INFORM); inform.setContent(String.valueOf(estrategia.getPuja())); } else { logger.log(Logger.FINE, myAgent.getLocalName() + " : Envía : INFORM : " + puja); return inform; } } logger.log(Logger.FINE, myAgent.getLocalName() + " : Envía : REFUSE"); return refuse; ACLMessage refuse = cfp.createReply(); refuse.setPerformative(ACLMessage.REFUSE); refuse.setContent(String.valueOf(estrategia.getPuja())); -80/106- } /** * Calcula la puja que ofertará el comprador * * @return El valor de la puja */ private double obtenerPuja(Double pujaActual) { double incremento = estrategia.getIncremento(); int tipoIncremento = estrategia.getTipoIncemento(); double puja = estrategia.getPuja(); while (puja < pujaActual) { if (tipoIncremento == 0) { puja = puja + incremento; } else { puja = Math.round(puja * incremento); } logger.log(Logger.FINE, myAgent.getLocalName() + " Calculando nueva puja:" + puja); } return puja; } /** * Comprueba si la puja es aceptable en base a la estrategia del comprador y * su precio de reserva * * @param puja * El importe de la puja * @return true si la puja es aceptable y fase en caso contrario */ private boolean pujaAceptable(double puja) { return ((puja < estrategia.getReserva()) && ((puja > estrategia .getPuja()) || (contadorPujas == 0))); } -81/106- Clase CompradorHolandesaNRondasBehaviour package uoc.sma.behaviours.estrategias; import uoc.sma.agentes.AgenteComprador; import uoc.sma.estrategias.ApuestaUnicaNRondasCfgImpl; import jade.core.Agent; import jade.domain.FIPAAgentManagement.FailureException; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.proto.SSIteratedContractNetResponder; import jade.util.Logger; /** * Estrategia del comprador de la subasta holandesa en la que al principio el * agente considera pujar en la subasta por el precio configurado en su atributo * Puja. Si en el transcurso de la subasta se supera el número de rondas * configurado en la estrategia entonces el valor de aceptación de la puja será * el de su precio de reserva. * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class CompradorHolandesaNRondasBehaviour extends SSIteratedContractNetResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AgenteComprador agente; private ApuestaUnicaNRondasCfgImpl estrategia; private double puja = 0; public CompradorHolandesaNRondasBehaviour(Agent a, ACLMessage cfp) { super(a, cfp); logger.setLevel(Logger.INFO); agente = (AgenteComprador) a; estrategia = (ApuestaUnicaNRondasCfgImpl) agente.getEstrategia(); } @Override /** * Trata las propuestas de compra del subastastador y envía un mensaje * PROPOSE en caso que acepte la oferta de venta o un mensaje REFUSE si * rechaza la oferta */ protected ACLMessage handleCfp(ACLMessage cfp) throws RefuseException, FailureException, NotUnderstoodException { ACLMessage firstPropose = cfp.createReply(); estrategia.setContadorRondas(estrategia.getContadorRondas() + 1); puja = Double.parseDouble(cfp.getContent()); if (pujaAceptable(puja)) { // Se acepta la puja firstPropose.setPerformative(ACLMessage.PROPOSE); logger.log(Logger.FINE, myAgent.getLocalName() + " : ENVIA : PROPOSE : " + puja); firstPropose.setContent(String.valueOf(puja)); -82/106- } } else { // No puja firstPropose.setPerformative(ACLMessage.REFUSE); logger.log(Logger.FINE, myAgent.getLocalName() + " : ENVIA : REFUSE : " + cfp.getContent()); } return firstPropose; @Override /** * Trata los mensajes de rechazo sobre una propuesta enviada al comprador */ protected void handleRejectProposal(ACLMessage cfp, ACLMessage propose, ACLMessage reject) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Recibe : REJECT"); if (reject == null) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Responder : TIMEOUT"); } } @Override /** * Trata los mensajes de aceptación de una propuesta de compra por parte del * comprador. * * Envía un mensaje INFORM cuando el subastador acepta la propuesta de * compra. * */ protected ACLMessage handleAcceptProposal(ACLMessage cfp, ACLMessage propose, ACLMessage accept) throws FailureException { logger.log(Logger.FINE, myAgent.getName() + " : Recibe : ACCEPT"); if (accept != null) { ACLMessage inform = accept.createReply(); inform.setPerformative(ACLMessage.INFORM); inform.setContent(String.valueOf(estrategia.getPuja())); } else { logger.log(Logger.FINE, myAgent.getLocalName() + " : Envía : INFORM : " + puja); return inform; } } logger.log(Logger.FINE, myAgent.getLocalName() + " : Envía : REFUSE"); return refuse; ACLMessage refuse = cfp.createReply(); refuse.setPerformative(ACLMessage.REFUSE); refuse.setContent(String.valueOf(estrategia.getPuja())); /** * Comprueba si la puja propuesta por el agente comprador es aceptable y si * el número de rondas es mayor o igual que el establecido entonces * incrementa el valor de la puja aceptable * * @param puja * El precio propuesto por el agente vendedor * @return */ private boolean pujaAceptable(double puja) { if (puja <= estrategia.getPuja()) -83/106- } } return true; if (estrategia.getContadorRondas() >= estrategia.getRondas() && estrategia.getReserva() != estrategia.getPuja()) { // Transcurridas n rodas se iguala la puja al precio de reserva estrategia.setPuja(estrategia.getReserva()); logger.log( Logger.FINE, myAgent.getLocalName() + ": se iguala el valor de la nueva puja aceptable al de la reserva:" + estrategia.getReserva()); return false; } else return false; //No interesa pujar Clase CompradorHolandesaIncrementoDinamicoBehaviour package uoc.sma.behaviours.estrategias; import uoc.sma.agentes.AgenteComprador; import uoc.sma.estrategias.ApuestaUnicaIncrementoDinamicoCfgImpl; import jade.core.Agent; import jade.domain.FIPAAgentManagement.FailureException; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.proto.SSIteratedContractNetResponder; import jade.util.Logger; /** * Estrategia del comprador de la subasta holandesa en la que en principio el * agente considera pujar en la subasta por el precio configurado en su atributo * Puja. Si se supera el número de rondas preestablecido en la estrategia * entonces incrementará el valor de aceptación de la puja en una cantidad fija * siempre y cuando no llegue al precio de reserva. * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class CompradorHolandesaIncrementoDinamicoBehaviour extends SSIteratedContractNetResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AgenteComprador agente; private ApuestaUnicaIncrementoDinamicoCfgImpl estrategia; private double puja = 0; public CompradorHolandesaIncrementoDinamicoBehaviour(Agent a, ACLMessage cfp) { super(a, cfp); logger.setLevel(Logger.INFO); agente = (AgenteComprador) a; estrategia = (ApuestaUnicaIncrementoDinamicoCfgImpl) agente .getEstrategia(); } -84/106- @Override /** * Trata las propuestas de compra del subastastador y envía un mensaje * PROPOSE en caso que acepte la oferta de venta o un mensaje REFUSE si * rechaza la oferta */ protected ACLMessage handleCfp(ACLMessage cfp) throws RefuseException, FailureException, NotUnderstoodException { ACLMessage firstPropose = cfp.createReply(); estrategia.setContadorRondas(estrategia.getContadorRondas() + 1); puja = Double.parseDouble(cfp.getContent()); if (pujaAceptable(puja)) { // Se acepta la puja firstPropose.setPerformative(ACLMessage.PROPOSE); logger.log(Logger.FINE, myAgent.getLocalName() + " : ENVIA : PROPOSE : " + puja); firstPropose.setContent(String.valueOf(puja)); } } else { // No puja firstPropose.setPerformative(ACLMessage.REFUSE); logger.log(Logger.FINE, myAgent.getLocalName() + " : ENVIA : REFUSE : " + cfp.getContent()); } return firstPropose; @Override /** * Trata los mensajes de rechazo sobre una propuesta enviada al comprador */ protected void handleRejectProposal(ACLMessage cfp, ACLMessage propose, ACLMessage reject) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Recibe : REJECT"); if (reject == null) { logger.log(Logger.FINE, myAgent.getLocalName() + " : Responder : TIMEOUT"); } } @Override /** * Trata los mensajes de aceptación de una propuesta de compra por parte del * comprador. * * Envía un mensaje INFORM cuando el subastador acepta la propuesta de * compra. * */ protected ACLMessage handleAcceptProposal(ACLMessage cfp, ACLMessage propose, ACLMessage accept) throws FailureException { logger.log(Logger.FINE, myAgent.getLocalName() + " : Recibe : ACCEPT"); if (accept != null) { ACLMessage inform = accept.createReply(); inform.setPerformative(ACLMessage.INFORM); inform.setContent(String.valueOf(estrategia.getPuja())); } else { logger.log(Logger.FINE, myAgent.getName() + " : Envía : INFORM : " + puja); return inform; -85/106- } ACLMessage refuse = cfp.createReply(); refuse.setPerformative(ACLMessage.REFUSE); refuse.setContent(String.valueOf(estrategia.getPuja())); } } logger.log(Logger.FINE, myAgent.getLocalName() + " : Envía : REFUSE"); return refuse; /** * Comprueba si la puja propuesta por el agente comprador es aceptable y si * el número de rondas es mayor o igual que el establecido entonces * incrementa el valor de la puja aceptable * * @param puja * El precio propuesto por el agente vendedor * @return */ private boolean pujaAceptable(double puja) { if (puja <= estrategia.getPuja()) return true; if (estrategia.getContadorRondas() >= estrategia.getRondas()) { if ((estrategia.getPuja() + estrategia.getIncremento()) > estrategia .getReserva()) { // La nueva puja aceptable supera el precio de reserva logger.log(Logger.FINE, myAgent.getLocalName() + ": el valor de la nueva puja aceptable " + (estrategia.getPuja() + estrategia.getIncremento()) + " supera la reserva " + estrategia.getReserva()); return false; } else { // Calcula la puja aceptable para la nueva ronda estrategia.setPuja(estrategia.getPuja() + estrategia.getIncremento()); logger.log( Logger.FINE, myAgent.getLocalName() + ": recalculando el valor de la nueva puja aceptable a:" + estrategia.getPuja() + estrategia.getIncremento()); return false; } } else return false; //No interesa pujar } -86/106- Clase BuscadorBehaviourInitiator package uoc.sma.behaviours; import java.io.IOException; import java.util.Vector; import uoc.sma.datos.Subasta; import jade.core.AID; import jade.core.Agent; import jade.domain.DFService; import jade.domain.FIPAException; import jade.domain.FIPANames; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.lang.acl.ACLMessage; import jade.lang.acl.UnreadableException; import jade.proto.AchieveREInitiator; import jade.proto.AchieveREResponder; import jade.util.Logger; /** * Comportamiento del Agente buscador. Forma parte del protocolo FIPA‐Brokering * * Recibe: * ‐Mensajes del Agente CasaSubastas * que contienen el resultado de la búsqueda * * Envía: * ‐Mensajes de petición al Agente CasaSubastas * solicitando una búsqueda de subastas * * ‐Mensajes de respuesta al Agente Comprador * con el resultado de la búsqueda * * @author Rodofo de Benito * */ public class BuscadorBehaviourInitiator extends AchieveREInitiator { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); private AID idCasaSubastas; public BuscadorBehaviourInitiator(Agent a, ACLMessage mt) { super(a, mt); logger.setLevel(Logger.INFO); // Localizar al Agente de Subastas en las páginas amarillas DFAgentDescription[] aCasaSubastas = getCasaSubastas(); if (aCasaSubastas != null) this.idCasaSubastas = aCasaSubastas[0].getName(); } /** * Construye la pregunta al Agente CasaSubastas en base a la * pregunta del Agente Comprador */ protected Vector prepareRequests(ACLMessage request) { // Recupera la petición entrante del DataStore String clavePeticionEntrada = (String) ((AchieveREResponder) parent).REQUEST_KEY; ACLMessage peticionEntrada = (ACLMessage) getDataStore().get(clavePeticionEntrada); -87/106- } // Prepara la petición para enviarsela al Agente CasaSubastas logger.log(Logger.FINE,"Agente " + myAgent.getLocalName() + ": Redirigiendo the petición a " + idCasaSubastas.getName()); ACLMessage peticionSalida = new ACLMessage(ACLMessage.QUERY_REF); peticionSalida.setProtocol(FIPANames.InteractionProtocol.FIPA_QUERY); peticionSalida.addReceiver(idCasaSubastas); peticionSalida.setContent(peticionEntrada.getContent()); peticionSalida.setReplyByDate(peticionEntrada.getReplyByDate()); Vector v = new Vector(1); v.addElement(peticionSalida); return v; protected void handleInform(ACLMessage inform) { guardarMensaje(ACLMessage.INFORM); } protected void handleRefuse(ACLMessage refuse) { guardarMensaje(ACLMessage.FAILURE); } protected void handleNotUnderstood(ACLMessage notUnderstood) { guardarMensaje(ACLMessage.FAILURE); } protected void handleFailure(ACLMessage failure) { guardarMensaje(ACLMessage.FAILURE); } protected void handleAllResultNotifications(Vector notificaciones) { if (notificaciones.size() == 0) { // Timeout guardarMensaje(ACLMessage.FAILURE); } } /** * Trata los mensajes recibidos y gestiona el Datastore * para recuperar los mensajes recibidos y almacenar * mensajes de respuesta * * @param performative */ private void guardarMensaje(int performative) { Subasta subasta=null; if (performative == ACLMessage.INFORM) { logger.log(Logger.INFO,"Agente " + myAgent.getLocalName() + ": Redirección conseguida"); } else { logger.log(Logger.INFO,"Agente " + myAgent.getLocalName() + ": Fallo en la redirección "); } // Recupera la petición entrante del DataStore. El mensaje del agente comprador String clavePeticionEntrada = (String) ((AchieveREResponder) parent).REQUEST_KEY; ACLMessage peticionEntrada = (ACLMessage) getDataStore().get(clavePeticionEntrada); //Recupera del DataStore la respuesta del agente CasaDeSubastas ACLMessage respuestaCasaSubastas = (ACLMessage) getDataStore().get(REPLY_KEY); // Prepara el mensaje para el Agente Comprador y la almacena en el DataStore ACLMessage mensaje = peticionEntrada.createReply(); mensaje.setPerformative(performative); try { if (respuestaCasaSubastas.getContentObject()!=null) { -88/106- } } subasta = (Subasta) respuestaCasaSubastas.getContentObject(); mensaje.setContentObject(subasta); } } catch (IOException e) { e.printStackTrace(); } catch (UnreadableException e) { e.printStackTrace(); } String notificationkey = (String) ((AchieveREResponder) parent).RESULT_NOTIFICATION_KEY; getDataStore().put(notificationkey, mensaje); /** * Localiza al agente CasaSubastas en las páginas amarillas * @return */ private DFAgentDescription[] getCasaSubastas() { DFAgentDescription template = new DFAgentDescription(); DFAgentDescription[] result = null; ServiceDescription sd = new ServiceDescription(); sd.setType("CasaDeSubastas"); template.addServices(sd); try { result = DFService.search(myAgent, template); } catch (FIPAException fe) { fe.printStackTrace(); } return result; } -89/106- Clase CompradorSuscribirBehaviourInitiator package uoc.sma.behaviours; import java.util.Vector; import uoc.sma.agentes.AgenteComprador; import jade.core.AID; import jade.core.Agent; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.SubscriptionInitiator; import jade.util.Logger; @SuppressWarnings("serial") /** * Clase que modela el comportamiento del comprador como suscriptor * de una subasta. * * Sigue el protocolo FIPA‐Subscription con el rol de Initiator * */ public class CompradorSuscribirBehaviourInitiator extends SubscriptionInitiator { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); public CompradorSuscribirBehaviourInitiator(Agent agente, ACLMessage mensaje) { super(agente, mensaje); logger.setLevel(Logger.INFO); } @Override /* * Se encarga de crear el mensaje de suscripción para un subastador * determinado y una subasta concreta */ protected Vector prepareSubscriptions(ACLMessage subscription) { subscription.addReceiver(((AgenteComprador) myAgent).getSubasta() .getAgenteSubastador()); // El identificador del subastador subscription.setContent(String.valueOf(((AgenteComprador) myAgent) .getSubasta().getIdSubasta())); //El id de la subasta a la que se suscribe logger.log(Logger.FINE, "Agente " + myAgent.getLocalName() + ": Creando mensaje de suscripcion " + subscription); return super.prepareSubscriptions(subscription); } protected void handleAgree(ACLMessage inform) { logger.log(Logger.FINE, myAgent.getLocalName() + ": Solicitud aceptada."); } protected void handleRefuse(ACLMessage inform) { logger.log(Logger.FINE, myAgent.getLocalName() + ": Solicitud rechazada."); } protected void handleInform(ACLMessage inform) { logger.log(Logger.FINE, myAgent.getLocalName() + ": Informe recibido: " + inform.getContent() + "\n"); } -90/106- } protected void handleFailure(ACLMessage failure) { //Se comprueba si el fallo viene del AMS o de otro agente. if (failure.getSender().equals(myAgent.getAMS())) { logger.log(Logger.INFO, myAgent.getLocalName() + ": El agente no existe."); } else { logger.log(Logger.INFO, myAgent.getLocalName() + ": El agente " + failure.getSender().getName() + " falló al intentar realizar la acción solicitada.\n"); } } public void cancellationCompleted(AID agente) { //Se crea una plantilla para solo recibir los mensajes del agente que va a cancelar la suscripción MessageTemplate template = MessageTemplate.MatchSender(agente); ACLMessage msg = myAgent.blockingReceive(template); } //Se comprueba que tipo de mensaje llega: INFORM o FAILURE if (msg.getPerformative() == ACLMessage.INFORM) logger.log(Logger.INFO, myAgent.getLocalName() + ": Suscripcion cancelada con el agente " + agente.getLocalName() + "\n"); else logger.log( Logger.INFO, myAgent.getLocalName() + ": Se ha producido un fallo en la cancelación con el agente " + agente.getLocalName() + "\n"); Clase SubastadorTransaccionesBehaviourInitiator package uoc.sma.behaviours; import jade.core.Agent; import jade.lang.acl.ACLMessage; import jade.proto.AchieveREInitiator; /** * Comportamiento del Agente buscador * implementa FIPA‐Query * * Se utiliza para enviar la transacción que debe registrar el agente CasSubastas * * * @author Rodofo de Benito */ public class SubastadorTransaccionesBehaviourInitiator extends AchieveREInitiator { public SubastadorTransaccionesBehaviourInitiator(Agent a, ACLMessage mt) { super(a, mt); } } -91/106- Clase BuscadorBehaviourResponder package uoc.sma.behaviours; import jade.core.Agent; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.AchieveREResponder; import jade.util.Logger; /** * Comportamiento del Agente buscador que forma parte del protocolo FIPA‐Brokering * * Envía: * ‐Mensajes de respuesta AGREE al Agente Comprador cuando recibe una * petición de búsqueda * * * @author Rodofo de Benito * */ public class BuscadorBehaviourResponder extends AchieveREResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); public BuscadorBehaviourResponder(Agent a, MessageTemplate mt) { super(a, mt); logger.setLevel(Logger.INFO); } protected ACLMessage prepareResponse(ACLMessage request) throws NotUnderstoodException, RefuseException { logger.log(Logger.FINE,"Agente " + myAgent.getLocalName() + ": Petición recibida de " + request.getSender().getName() + ". La acción es " + request.getContent()); ACLMessage agree = request.createReply(); agree.setPerformative(ACLMessage.AGREE); return agree; } } -92/106- Clase CasaSubastasBusquedasBehaviourResponder package uoc.sma.behaviours; import java.io.IOException; import uoc.sma.agentes.AgenteCasaSubastas; import uoc.sma.datos.Subasta; import jade.core.Agent; import jade.domain.FIPAAgentManagement.FailureException; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.AchieveREResponder; import jade.util.Logger; /** * Comportamiento del Agente CasaSubastas que se encarga de responder a la * petición de búsquedas de subastas del Agente Buscador * * Implementa FIPa‐Query con el rol de Participant * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class CasaSubastasBusquedasBehaviourResponder extends AchieveREResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); public CasaSubastasBusquedasBehaviourResponder(Agent a, MessageTemplate mt) { super(a, mt); logger.setLevel(Logger.FINE); } /** * Prepara el mensaje de respuesta al agente buscador confirmando que ha * recibido la petición de búsqueda */ protected ACLMessage prepareResponse(ACLMessage request) throws NotUnderstoodException, RefuseException { logger.log(Logger.FINE, "Agente " + myAgent.getLocalName() + ": Petición recibida de " + request.getSender().getName() + ". Acción es " + request.getContent()); logger.log(Logger.FINE, "Agente " + myAgent.getLocalName() + ": Agree"); ACLMessage agree = request.createReply(); agree.setPerformative(ACLMessage.AGREE); return agree; } /** * Prepara el mensage de respuesta al agente buscador con el resultado de la * búsqueda */ protected ACLMessage prepareResultNotification(ACLMessage request, ACLMessage response) throws FailureException { logger.log(Logger.FINE, "Agente " + myAgent.getLocalName() + ": Búsqueda realizada satisfactoriamente"); Subasta s = ((AgenteCasaSubastas) myAgent).getSubasta(request .getContent().toUpperCase()); -93/106- } } ACLMessage inform = request.createReply(); inform.setPerformative(ACLMessage.INFORM); try { inform.setContentObject(s); } catch (IOException e) { e.printStackTrace(); } return inform; Clase SubastadorSuscribirBehaviourResponder package uoc.sma.behaviours; import uoc.sma.agentes.AgenteSubastador; import jade.core.Agent; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.SubscriptionResponder; import jade.util.Logger; /** * Procesa los mensajes relacionados con la suscripción de Agentes Compradores a una subasta * * Implementa el protocolo FIPA‐Subscribe con el rol de Participant * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class SubastadorSuscribirBehaviourResponder extends SubscriptionResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); public SubastadorSuscribirBehaviourResponder(Agent a, MessageTemplate mt, SubscriptionManager sm) { super(a, mt, sm); logger.setLevel(Logger.INFO); } private Subscription suscripcion; /** * Método que gestiona la suscripcion aceptando/rechazando las * propuestas de suscripción a la subasta */ protected ACLMessage handleSubscription(ACLMessage propuesta) throws NotUnderstoodException { logger.log(Logger.FINE, myAgent.getLocalName() + ": SUSCRIBE recibido de " + propuesta.getSender().getLocalName() + "\n"); logger.log(Logger.FINE, myAgent.getLocalName() + " La propuesta es suscribirse a la subastas Id:" + myAgent.getLocalName(), propuesta.getContent() + "\n"); //Comprueba los datos de la propuesta if (((AgenteSubastador) myAgent).compruebaMensaje(propuesta .getContent())) { //Crea la suscripcion this.suscripcion = this.createSubscription(propuesta); -94/106- } try { //El SubscriptionManager registra la suscripcion this.mySubscriptionManager.register(suscripcion); } catch (Exception e) { logger.log(Logger.FINE, myAgent.getLocalName() + ": Error en el registro de la suscripción."); } } } else { } //Acepta la propuesta y la envía ACLMessage agree = propuesta.createReply(); agree.setPerformative(ACLMessage.AGREE); return agree; //Rechaza la propuesta y la envía logger.log(Logger.FINE, myAgent.getLocalName() + ": Rechaza la propuesta de suscripción."); ACLMessage refuse = propuesta.createReply(); refuse.setPerformative(ACLMessage.REFUSE); return refuse; /** * Gestiona la cancelación de la subasta */ protected ACLMessage handleCancel(ACLMessage cancelacion) { logger.log(Logger.FINE, myAgent.getLocalName() + "%s: CANCEL recibido de " + cancelacion.getSender().getLocalName() + "\n"); try { //El SubscriptionManager elimina del registro la suscripcion this.mySubscriptionManager.deregister(this.suscripcion); } catch (Exception e) { logger.log( Logger.FINE, myAgent.getLocalName() + ": Error en la operación de anluar la suscripción de la suscripción."); } } //Acepta la cancelación y responde ACLMessage cancela = cancelacion.createReply(); cancela.setPerformative(ACLMessage.INFORM); return cancela; -95/106- Clase CasaSubastasTransaccionesBehaviourResponder package uoc.sma.behaviours; import uoc.sma.agentes.AgenteCasaSubastas; import uoc.sma.datos.Transaccion; import jade.core.Agent; import jade.domain.FIPAAgentManagement.NotUnderstoodException; import jade.domain.FIPAAgentManagement.RefuseException; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.lang.acl.UnreadableException; import jade.proto.AchieveREResponder; import jade.util.Logger; /** * Comportamiento del Agente CasaSubastas que se encarga de atender las * peticiones de insercción de una transacción en el historial de transacciones * * Implementa FIPA‐Query con el rol de Participant * * @author Rodolfo de Benito * */ @SuppressWarnings("serial") public class CasaSubastasTransaccionesBehaviourResponder extends AchieveREResponder { private final Logger logger = Logger.getMyLogger(this.getClass().getName()); public CasaSubastasTransaccionesBehaviourResponder(Agent a, MessageTemplate mt) { super(a, mt); logger.setLevel(Logger.INFO); } /** * Atiende los mensajes de petición de registro de una trnasacción * procedentes de un agente subastador */ protected ACLMessage handleRequest(ACLMessage request) throws NotUnderstoodException, RefuseException { Transaccion t = null; try { t = (Transaccion) request.getContentObject(); logger.log(Logger.FINE,"Agente " + myAgent.getLocalName() + ": Petición recibida de " + request.getSender().getName() + ". Transacción " + t); } catch (UnreadableException e) { e.printStackTrace(); } // Registra la transacción ((AgenteCasaSubastas) myAgent).addTransaccion(t); logger.log(Logger.FINE,"Agente " + myAgent.getLocalName() + ": Agree"); ACLMessage agree = request.createReply(); agree.setPerformative(ACLMessage.AGREE); return agree; } } -96/106- Interface ICfgApuesta package uoc.sma.estrategias; import jade.core.behaviours.Behaviour; /** * Encapsula la estrategia que seguirá el agente comprador * * La finalidad de este interface es ser implementado por las * clases que representan las diferentes estrategias que seguirá * el agente comprador. * * @author Rodolfo de Benito Arango * */ public interface ICfgApuesta { /** * Establece el comportamiento en el agente comprador * que se le pasa como referencia * * @param agente */ public void setComportamiento(Behaviour comportamiento); /** * Retorna una referencia al comportamiento o estrategia que * seguirá el comprador * * @return */ public Behaviour getComportamiento(); } -97/106- Interface ICfgSubasta package uoc.sma.estrategias; import jade.core.behaviours.Behaviour; /** * Encapsula la estrategia que seguirá el agente subastador * * La finalidad de este interface es ser implementado por las * clases que representan los tipos de subastas. * * @author Rodolfo de Benito Arango * */ public interface ICfgSubasta { /** * Establece el comportamiento en el agente subastador * que se le pasa como referencia * * @param agente */ public void setComportamiento(Behaviour comportamiento); /** * Retorna una referencia al comportamiento o estrategia que * seguirá el subastador * * @return */ public Behaviour getComportamiento(); } Clase IncrementalCfgImpl package uoc.sma.estrategias; import uoc.sma.behaviours.estrategias.CompradorInglesaIncrementalBehaviour; import jade.core.behaviours.Behaviour; /** * Encapsula la estrategia de una puja inicial que cada cierto tiempo * se va incrementando en una cantidad fija sin que la puja llegue a * superar el precio de reserva marcado por el comprador * * @author Rodolfo de Benito * */ public class IncrementalCfgImpl implements ICfgApuesta{ public final int INCREMENTOARITMETICO = 0; public final int INCREMENTOGEOMETRICO = 1; private int tipoIncremento; private double incremento; //Incremento de la puja private double puja; private double reserva; //La puja máxima a la que llegará el agente private CompradorInglesaIncrementalBehaviour comportamiento; public IncrementalCfgImpl(int tipoIncemento, double incremento, double puja, double reserva) { -98/106- } super(); this.tipoIncremento = tipoIncemento; this.incremento = incremento; this.puja = puja; this.reserva = reserva; public Behaviour getComportamiento() { return comportamiento; } public void setComportamiento(Behaviour comportamiento) { this.comportamiento=(CompradorInglesaIncrementalBehaviour)comportamiento; } public int getTipoIncemento() { return tipoIncremento; } public void setTipoIncemento(int tipoIncemento) { this.tipoIncremento = tipoIncemento; } public double getIncremento() { return incremento; } public void setIncremento(double incremento) { this.incremento = incremento; } public double getPuja() { return puja; } public void setPuja(double puja) { this.puja = puja; } public double getReserva() { return reserva; } public void setReserva(double reserva) { this.reserva = reserva; } } Clase ApuestaUnicaNRondasCfgImpl package uoc.sma.estrategias; import uoc.sma.behaviours.estrategias.CompradorHolandesaNRondasBehaviour; import jade.core.behaviours.Behaviour; -99/106- /** * Encapsula la estrategia de una única puja * * En principio el agente considera pujar en la subasta por el precio configurado en su atributo Puja * Si se supera el número de rondas "Rondas" entonces el valor de aceptación de la puja será el * de su precio de reserva * * @author Rodolfo de Benito * */ public class ApuestaUnicaNRondasCfgImpl implements ICfgApuesta { private double incremento; //Incremento del valor de aceptación de la puja private double puja; //Valor de aceptación por el que está dispuesto a pujar si no se alcanza el número de rondas estipulado private double reserva; //La puja máxima a la que llegará el agente private int rondas; //Número de rondas que esperará para subir el valor de aceptación de la puja private int contadorRondas; //Contabiliza el número de rondas que lleva un comprador en una subasta private CompradorHolandesaNRondasBehaviour comportamiento; public ApuestaUnicaNRondasCfgImpl(double incremento, double puja, double reserva, int rondas) { super(); this.incremento = incremento; this.puja = puja; this.reserva = reserva; this.rondas=rondas; this.contadorRondas=0; } public Behaviour getComportamiento() { return comportamiento; } public void setComportamiento(Behaviour comportamiento) { this.comportamiento=(CompradorHolandesaNRondasBehaviour)comportamiento; } public int getRondas() { return rondas; } public void setRondas(int rondas) { this.rondas = rondas; } public double getIncremento() { return incremento; } public void setIncremento(double incremento) { this.incremento = incremento; } public double getPuja() { return puja; } public void setPuja(double puja) { -100/106- } } this.puja = puja; public double getReserva() { return reserva; } public void setReserva(double reserva) { this.reserva = reserva; } public int getContadorRondas() { return contadorRondas; } public void setContadorRondas(int contadorRondas) { this.contadorRondas = contadorRondas; } Clase ApuestaUnicaIncrementoDinamicoCfgImpl package uoc.sma.estrategias; import uoc.sma.behaviours.estrategias.CompradorHolandesaIncrementoDinamicoBehaviour; import jade.core.behaviours.Behaviour; /** * Encapsula la estrategia de una única puja * * En principio el agente considera pujar en la subasta por el precio configurado en su atributo Puja * Si se supera el número de rondas "Rondas" entonces incrementará el valor de aceptación de la puja * siempre y cuando no llegue al precio de reserva * * @author Rodolfo de Benito * */ public class ApuestaUnicaIncrementoDinamicoCfgImpl implements ICfgApuesta { private double incremento; //Incremento del valor de aceptación de la puja private double puja; //Valor de aceptación por el que está dispuesto a pujar si no se alcanza el número de rondas estipulado private double reserva; //La puja máxima a la que llegará el agente private int rondas; //Número de rondas que esperará para subir el valor de aceptación de la puja private int contadorRondas; //Contabiliza el número de rondas que lleva un comprador en una subasta private CompradorHolandesaIncrementoDinamicoBehaviour comportamiento; public ApuestaUnicaIncrementoDinamicoCfgImpl(double incremento, double puja, double reserva, int rondas) { super(); this.incremento = incremento; this.puja = puja; this.reserva = reserva; this.rondas=rondas; this.contadorRondas=0; } public Behaviour getComportamiento() { return comportamiento; } -101/106- } public void setComportamiento(Behaviour comportamiento) { this.comportamiento=(CompradorHolandesaIncrementoDinamicoBehaviour)comportamiento; } public int getRondas() { return rondas; } public void setRondas(int rondas) { this.rondas = rondas; } public double getIncremento() { return incremento; } public void setIncremento(double incremento) { this.incremento = incremento; } public double getPuja() { return puja; } public void setPuja(double puja) { this.puja = puja; } public double getReserva() { return reserva; } public void setReserva(double reserva) { this.reserva = reserva; } public int getContadorRondas() { return contadorRondas; } public void setContadorRondas(int contadorRondas) { this.contadorRondas = contadorRondas; } -102/106- Clase SubastaHolandesaImpl package uoc.sma.estrategias; import uoc.sma.behaviours.estrategias.SubastadorHolandesaBehaviour; import jade.core.behaviours.Behaviour; /** * Encapsula la configuración de la subasta Holandesa * * @author Rodolfo de Benito Arango * */ public class SubastaHolandesaImpl implements ICfgSubasta { private SubastadorHolandesaBehaviour comportamiento; public Behaviour getComportamiento() { return comportamiento; } public void setComportamiento(Behaviour comportamiento) { this.comportamiento= (SubastadorHolandesaBehaviour) comportamiento; } } Clase SubastaInglesaImpl package uoc.sma.estrategias; import uoc.sma.behaviours.estrategias.SubastadorInglesaBehaviour; import jade.core.behaviours.Behaviour; /** * Encapsula la configuración de la subasta Inglesa * * @author Rodolfo de Benito Arango * */ public class SubastaInglesaImpl implements ICfgSubasta { private SubastadorInglesaBehaviour comportamiento; public Behaviour getComportamiento() { return comportamiento; } public void setComportamiento(Behaviour comportamiento) { this.comportamiento= (SubastadorInglesaBehaviour) comportamiento; } } -103/106- Clase Subasta package uoc.sma.datos; import jade.core.AID; import jade.lang.acl.ACLMessage; import jade.util.leap.Serializable; import java.util.ArrayList; import java.util.Date; /** * Clase que encapsula los datos propios de la subasta * * @author Rodolfo de Benito */ public class Subasta implements Serializable{ public static final int SUBASTA_INGLESA=1; public static final int SUBASTA_HOLANDESA=2; private static final long serialVersionUID = 1L; private int idSubasta; private Date fechaInicio; private AID agenteSubastador; private String objetoSubastado; private double precio; private double precioReserva; private boolean activa; private int tipoSubasta; private AID ganador; private ACLMessage msgMejorOferta; private ArrayList<AID> suscriptores; public Subasta(int idSubasta, Date fechaInicio, String objetoSubastado, double precio, double precioReserva, boolean activa, int tipoSubasta) { super(); this.idSubasta = idSubasta; this.fechaInicio = fechaInicio; this.objetoSubastado = objetoSubastado; this.precio = precio; this.precioReserva = precioReserva; this.activa = activa; this.tipoSubasta = tipoSubasta; suscriptores = new ArrayList<AID>(); } public ACLMessage getMsgMejorOferta() { return msgMejorOferta; } public void setMsgMejorOferta(ACLMessage msgMejorOferta) { this.msgMejorOferta = msgMejorOferta; } public double getPrecio() { return precio; } public void setPrecio(double precio) { this.precio = precio; } -104/106- } public int getIdSubasta() { return idSubasta; } public void setIdSubasta(int idSubasta) { this.idSubasta = idSubasta; } public Date getFechaInicio() { return fechaInicio; } public void setFechaInicio(Date fechaInicio) { this.fechaInicio = fechaInicio; } public String getObjetoSubastado() { return objetoSubastado; } public void setObjetoSubastado(String objetoSubastado) { this.objetoSubastado = objetoSubastado; } public double getPrecioReserva() { return precioReserva; } public void setPrecioReserva(double precioReserva) { this.precioReserva = precioReserva; } public boolean isActiva() { return activa; } public void setActiva(boolean activa) { this.activa = activa; } public int getTipoSubasta() { return tipoSubasta; } public void setTipoSubasta(int tipoSubasta) { this.tipoSubasta = tipoSubasta; } public AID getAgenteSubastador() { return agenteSubastador; } public void setAgenteSubastador(AID agenteSubastador) { this.agenteSubastador = agenteSubastador; } public AID getGanador() { return ganador; } public void setGanador(AID ganador) { this.ganador = ganador; } public ArrayList<AID> getSuscriptores() { return suscriptores; } public void setSuscriptores(ArrayList<AID> suscriptores) { this.suscriptores = suscriptores; } @Override public String toString() { String cadena; cadena="Subasta Id:"+getIdSubasta()+ " "+getObjetoSubastado()+" Precio:"+getPrecio()+" Inicio:"+getFechaInicio(); return cadena; } -105/106- Clase Transacción package uoc.sma.datos; import java.io.Serializable; import java.util.Date; /** * Encapsula los datos de una transacción u operación realizada en una subasta * @author Rodolfo de Benito */ public class Transaccion implements Serializable{ private Date fecha; private int idSubasta; private String agente; private String operación; private double valor; public static final String PUJA="PUJA"; public static final String OFERTA = "OFERTA"; public static final String INICIO = "INICIO"; public static final String FIN = "FIN"; public Transaccion(Date fecha, int idSubasta, String agente, String operación, double valor) { super(); this.fecha = fecha; this.idSubasta = idSubasta; this.agente = agente; this.operación = operación; this.valor = valor; } public Date getFecha() { return fecha; } public void setFecha(Date fecha) { this.fecha = fecha; } public int getIdSubasta() { return idSubasta; } public void setIdSubasta(int idSubasta) { this.idSubasta = idSubasta; } public String getAgente() { return agente; } public void setAgente(String agente) { this.agente = agente; } public String getOperación() { return operación; } public void setOperación(String operación) { this.operación = operación; } public double getValor() { return valor; } public void setValor(double valor) { this.valor = valor; } public String toString() { String cadena="Transacción Fecha:"+getFecha()+" Id. subasta:"+getIdSubasta()+" Agente:" +getAgente()+" Operación:"+getOperación()+" Valor:"+getValor(); return cadena; } } -106/106-