Curso de Agentes Jade Con JSF y Hibernate

Share Embed Donate


Short Description

Download Curso de Agentes Jade Con JSF y Hibernate...

Description

Curso de Agentes Jade con JSF y Hibernate 1 Contenido 1

¿Qué es un agente de Software? ................................................................................................ 3

2

Diferencia entre objetos y agentes: ............................................................................................ 3 2.1

Propiedades de un agente: ................................................................................................. 3

3

¿Qué no es agente? ..................................................................................................................... 3

4

Introducción ................................................................................................................................ 4

1.

Características del framework JADE............................................................................................ 4

2.

Plataforma de Agentes JADE ....................................................................................................... 5

3.

Instalación y ejecución de la plataforma JADE ............................................................................ 8 3.1.

Distribución e Instalación: ................................................................................................ 8



Distribución ......................................................................................................................... 8



Configuración de jade en Windows .................................................................................... 8

3.2.

Ejecución de la plataforma JADE e interfaces gráficas para usuarios. .......................... 9

3.3.

Iniciar un Agente en la Plataforma JADE: ..................................................................... 11

3.4.

Sintaxis de línea de comandos: ....................................................................................... 12

4.

Opciones de comando de líneas: ............................................................................................ 12

5.

Ejecución remota ..................................................................................................................... 16

6.

7.

5.1.

Adherir una plataforma................................................................................................... 16



Por el protocolo IIOP ......................................................................................................... 16



Por el protocolo HTTP en una LAN .................................................................................... 18



Jade, Lans y routers ........................................................................................................... 19

Programar agentes en JADE .................................................................................................... 19 6.1.

Ciclo de vida de un agente............................................................................................... 20

6.2.

Estados de un agente ....................................................................................................... 20

6.3.

Transiciones entre estados: ............................................................................................ 21

Programación de Agentes Jade ............................................................................................... 23 7.1.

Ejemplo de ejecución de agentes JADE mediante la consola de comando: ................. 24

7.2.

Como crear un Agente en código: ................................................................................... 25

7.2.1.

A partir de otro agente:............................................................................................. 25

7.2.2. 8.

A partir de una aplicación Java:................................................................................. 26

Mensajes entre Agentes: ......................................................................................................... 28 Envió y Recepción de mensajes ...................................................................................... 29

8.1.

9.

8.1.1.

Metodos de ACLMessage: ......................................................................................... 30

8.1.2.

Enviar un mensaje ..................................................................................................... 34

8.1.3.

Recepción del mensaje ............................................................................................. 35

8.1.4.

Ejemplo de intercambio de mensajes entre dos agentes: ...................................... 35

8.1.5.

Metodos bolck y blockingReceive ............................................................................ 38

Parte grafica de un Agente seda con la extensión GuiAgent ................................................ 38

10.

Comportamientos o Behaviour........................................................................................... 40

10.1.

Añadir y eliminar comportamientos ..................................................................... 41

10.2.

Métodos de un comportamiento ............................................................................ 43

10.2.1.

Método action(): ....................................................................................................... 44

10.2.2.

Método done(): ......................................................................................................... 44

10.2.3.

Método block(): ......................................................................................................... 45

10.2.4.

Método blockReceive(): ............................................................................................ 46

10.2.5.

Métodos onStart() y onEnd(): ................................................................................... 46

10.3. 11.

Ejecución de los comportamientos ........................................................................ 47

Java Server Faces (JSF) ........................................................................................................ 48

11.1.

Ejemplos de paginas JSF ........................................................................................... 50

11.2.

Estructura de una aplicación JSF ............................................................................ 52

11.3.

Patrón MVC ................................................................................................................. 53

12.

Hibernate.............................................................................................................................. 54

13.

Proyecto Web de Agentes jade con las tecnologías JSF y Hibernate ............................... 77

14.

Ingenias (IDK) ...................................................................................................................... 87

15.

Bibliogafia. ............................................................................................................................ 94

1

¿Qué es un agente de Software?

“Los agentes son sistemas computacionales que habitan en entornos dinámicos complejos, perciben y actúan de forma autónoma en ese entorno, realizando un conjunto de tareas y cumpliendo objetivos para los cuales fueron diseñados.” (P. Maes) Además un agente pretende actuar como un usuario que busca cierta información de interés para el usuario real o para otro programa, lo cual es definido en sus comportamientos. Para Russell y Norvig un agente es cualquier cosa capaz de percibir su medioambiente mediante sensores y actuar en ese medio mediante actuadores. Todo agente tiene una función u objetivo. Por ejemplo, un agente humano de bolsa tiene el objetivo de comprar y vender acciones respondiendo a los estímulos iniciados por su cliente y captados por sus sentidos. Una aspiradora tiene la función de aspirar cuando capta que ha sido encendida y no aspirar cuando es apagada.

2

Diferencia entre objetos y agentes:

Los Objetos están definidos por sus métodos y atributos. Los Agentes están definidos por sus comportamientos.

2.1 Propiedades de un agente: Autónomo: Social: Reactivo Proactivo Movilidad Aprendizaje/Adaptación

3 ¿Qué no es agente? Un agente no es un programa tradicional, pues reaccionan al entorno, tiene autonomía y persistencia. Un agente no es un objeto, porque son más autónomos que estos, son más flexibles (reactivos, proactivos y sociales). Un agente no es un sistema experto, porque los sistemas expertos no se acoplan a su entorno, no están diseñados para tener comportamientos reactivos ni proactivos, ni tampoco tienen habilidad social. JADE (Java Agent DEvelopment Framework)

4 Introducción Esta implementado en el lenguaje java. Es un middleware donde se implementan sistema mulitiagentes de acuerdo a las especificaciones FIPA (Foundation for Intelligent Physical Agents). La plataforma puede ser distribuida en distintas maquinas (pueden no tener el mismo sistema operativo).

1. Características del framework JADE La siguiente es la lista de características que JADE ofrece al programador: Jade es una plataforma de agentes distribuida. Los agentes se implementan como hilos en Java y viven dentro de Agent Containers (contenedores de agente) que proporcionan el soporte para la ejecución del agente. Interfaz gráfica de usuario para administrar varios agentes y contenedores del agente desde un host remoto. Depuración de herramientas para ayudar en el desarrollo de aplicaciones basadas en múltiples agentes JADE. Intra-plataforma de agente de movilidad, incluida la transferencia del estado y el código (cuando sea necesario) del agente. Apoyo a la ejecución de las actividades de los agentes múltiples, paralelas y simultáneas a través del modelo de comportamiento. JADE coloca horarios a los comportamientos de los agentes en una manera no preferente. FIPA-compliant plataforma de agente, que incluye la AMS (Sistema de Gestión del agente) y el DF (Facilitador de directorio). Estos componentes se activan automáticamente en la plataforma de agentes al desplegarse. Muchos FIPA-compliant DFs se puede iniciar en tiempo de ejecución con el fin de implementar las aplicaciones multi-dominio, donde dominio es un conjunto lógico de los agentes, cuyos servicios se anuncian a través de un facilitador común. Cada DF hereda una interfaz gráfica de usuario y todas las capacidades estándar definidos por FIPA (es decir, capacidad de registrar, borrar el registro, la modificación y la búsqueda de descripciones de agente, y de la capacidad de federar dentro de una red de DF). Transporte eficiente de mensajes ACL dentro de la plataforma Jade. De hecho, los mensajes se transfieren codificados como objetos Java, en lugar de cadenas, con el fin de evitar la clasificación (marshalling) y la descalificación (unmarshalling) de procedimientos. Al cruzar los límites de la plataforma, el mensaje se convierte automáticamente a / desde la sintaxis compatible con FIPA, codificación y protocolo de transporte. Esta conversión es transparente a los agentes ejecutores que sólo tienen que lidiar con los objetos Java.

Biblioteca de protocolos de interacción FIPA listos para ser utilizados. El registro automático y la baja de los agentes con la AMS. FIPA-compliant servicio de nombres: en el arranque agentes obtienen su GUID (identificador único global) de la plataforma. Soporte para aplicaciones con contenido de lenguajes y ontologías. InProcess Interface to allow external applications to launch autonomous agents. (traducir)

2. Plataforma de Agentes JADE En este capítulo se describen las clases JADE que apoyan el desarrollo de sistemas multiagente. Garantiza el cumplimiento de JADE sintáctico y, en cumplimiento de lo posible, semántica con las especificaciones FIPA. El modelo estándar de una plataforma de agentes está definido por FIPA, como se representa en la Figura 1. Esta plataforma puede ser distribuida en diferentes host incluso con distintos sistemas operativos y la configuración puede ser controlada a través de una interfaz de usuario remota. Software

Plataforma de Agentes Agente

Agente administrador de Sistema (AMS)

El facilitador de la guía (DF)

Mensage

Transporte

Sistema

Mensage

Transporte

Sistema

Plataforma de Agentes Figura 1 Arquitectura de referencia para la Plataforma de Agentes FIPA

En esta plataforma se encuentran tres agente principales, los cuales se encargan de diversas tareas para el correcto funcionamiento de la plataforma. (ver Figura 2) El Agent Management System (AMS), este agente se encarga de la supervisar el acceso y utilización de la plataforma. Solo existe un AMS en toda la plataforma. El AMS provee las paginas blancas (white-pages) y el servicio de ciclo de vida (life-cycle), mantiene el directorio de los agentes identificados (AID) y su estado. Cada agente debe registrarse con un AMS a fin de obtener un AID valido. El Directory Facilitator (DF) este agente provee el servicio de páginas amarillas (yellow-pages) en la plataforma. Se encarga de publicar servicios de los agentes para que otros agentes puedan llamarlos y asi cumplir su objetivo(s). El Message Transport System, también se llama Agent Communication Channel (ACC), es el componente de software que controla todo el intercambio de mensajes dentro de la plataforma, incluidos los mensajes a/desde plataformasremotas. JADE cumple plenamente con esta arquitectura de referencia y cuando uno pone en marcha la plataforma JADE, el AMS y el DF se crean inmediatamente en un Contenedor Principal (MainContainer). Además, el servicio de mensajería (la ejecución del componente ACC) está siempre activada para permitir la comunicación basada en mensajes.

Figura 2

Cada instancia de la plataforma Jade se llama contenedor (container) la cual puede albergar a distintos agentes. Un conjunto de contenedores activos forman una plataforma. En cada plataforma existe un Contenedor Principal, este debe ser el primer contenedor en ejecutarse, ya que este registra a los demás contenedores que se ejecuten en dicha plataforma. En la Figura 3 se representa dos plataformas Jade comunicándose a través de la red/nube.

Figura 3

3. Instalación y ejecución de la plataforma JADE Requisitos: Tener instalado y configurado el jdk (Java Development Kit) http://www.oracle.com/technetwork/java/javase/downloads/index.html Descargar la distribución binaria de Jade de su página oficial, se debe tener una cuenta para poder realizar la descarga, esta cuenta es gratuita. http://jade.tilab.com/

3.1.Distribución e Instalación: 

Distribución En esta sección se asume que ha descargado la distribución binaria JADE (JADE-bin4.0.zip), la distribución de código fuente JADE (JADE-src-4.0.zip) y la distribución JADE ejemplos (JADE-examples-4.0.zip). Una vez que los haya descomprimido en su disco duro que debe terminar con una estructura de directorios similar a la siguiente:

Figura 4



Configuración de jade en Windows Descargar el archivo JADE-bin-4.0.zip de la página http://jade.tilab.com/ a la cual tendrán que inscribirse una vez descargado es solo descomprimirlo en cualquier parte del disco ejemplo c:\jade después se configura variables de entorno en Windows , propiedades del sistema - Opciones Avanzadas – Variables de Entorno: Luego en la parte de variables del sistema le dan Nueva : Nombre de Variable: CLASSPATH Valor de la variable: %CLASSPATH%;.;c:\jade\lib\jade.jar;c:\jade\lib\commonscodec\ commons-codec-1.3.jar

Figura 5

3.2.Ejecución de la plataforma JADE e interfaces gráficas para usuarios. Una vez instalada la plataforma ejecutamos cmd (Windows) y escribimos lo siguiente: java jade.Boot –gui (Figura 6).

Figura 6

Figura 7

Luego nos aparecerá JADE Remote Agent Management GUI el cual nos mostrara todos los agentes que se crearan o ya creados, para esto último si ya se han creado agentes sin haber iniciado primero el GUI se tendrá que escribir la siguiente línea, en la consola de comandos java jade.Boot –container –gui para que se logre ejecutar el GUI. (Figura 8)

Figura 8

En este caso el agente que se inició anterior al GUI es Mi_Agente. Agente Sniffer: Se utiliza para visualizar el envió de mensajes entre agentes. El usuario decide que agentes desea ver, y también permite guardar para un posterior análisis. Agente Dummy: Permite ver los mensajes enviados entre Agentes, también se puede editar, componer y enviar mensajes ACL a otros agentes. Recibe y visualiza los mensajes de otros agentes (almacena y recupera los mensajes). Agente Introspector: Permite dar un seguimiento al ciclo de vida de los agentes así como ver también los mensajes que este intercambio, muestra las colas de entrada y salida de mensajes. DF gui: Permite al usuario interactuar con el DF. Ver que agentes se encuentran registrados y que servicio brinda. Registra y des-registra agentes. Puedes Modificar los servicios de los agentes registrados. Búsqueda de agentes registrados. Federar el DF con otros DF’s y crear una red de dominios y subdominios de Páginas Amarillas.

3.3.Iniciar un Agente en la Plataforma JADE: Java jade.Boot –local-port 1099 NombredelAgente:“Nombre_paquete”.“La_clase_del_agente” (Argumentos)

Nombre del Agente: Se escribe cualquier nombre que se le desee poner al agente. Nombre del paquete: Se escribe el paquete en donde se encuentra la clase del agente. La clase del Agente: Ahí se coloca el nombre del archivo Java que se extiende a un Agent o a un GuiAgent. Argumentos: Se colocan palabras que ayudan al agente a realizar ciertas tareas, comportamientos, etc. que lo necesiten, funciona similar a los argumentos del método main de java. Son de tipo Objet[] En caso de haber ejecutado la plataforma jade antes de crear a los agentes será necesario agregar –container al código anterior:

Java jade.Boot –container NombredelAgente:“Nombre_paquete”.“La_clase_del_agente” (Argumentos)

Nota: esta sintaxis puede variar según la versión de jade.

3.4.Sintaxis de línea de comandos: Java jade.Boot [opciones] [Nombre_agente]:[Paquete.Clase_Agente]([Argumentos]); [Nombre_Agente2]:[Paquete.Clase_Agente]([Argumentos])

Los argumentos están separados por comas Las opciones pueden ser cualquiera de estas, según el requerimiento: -container -gui -host Y otras que se detallan a continuación.

4. Opciones de comando de líneas: -container: Se utiliza para definir un nuevo contenedor en el cual se crearan él o los agentes -host: Especifica el nombre del host (nombre del ordenador) donde se encuentra el contenedor principal de la plataforma, su valor por defecto es localhost. -port: Especifica un número de puerto donde se ejecuta el contenedor principal, este valor por defecto es el 1099. -gui: Ejecuta el RMA de jade con el puerto predeterminado 1099. -local-host: Específica el nombre de host en este contenedor que se va a ejecutar, y su valor es por defecto localhost. Un ejemplo típico de este tipo de uso es para incluir el dominio completo del host (por ejemplo, kim.cselt.it-host cuando el host local tendría que regresar 'Kim') de manera que el principal contenedor puede ser contactado incluso de fuera del dominio local. -local-port: Especifica un número de puerto que puede ser el predeterminado u otro, para la creacion de la plataforma jade. Valor por defecto 1099. -platform-id: Esta opción especifica el nombre simbólico de la plataforma, esta opción será considerada solo en el caso de un contenedor principal, el valor por defecto es generar un nombre único de los valores de nombre de host del contenedor principal y el número de puerto. -name: tal y como plataforma de Identificación (mantenido por compatibilidad hacia atrás). -container-name: Se ejecuta solo al momento de iniciar la plataforma jade y reemplaza el nombre del contenedor principal de jade “Main-Container” con el que se le coloco. -services: Especifica una lista de clases, la aplicación de JADE servicios a nivel de kernel, que se debe cargar y activar durante el arranque. Los nombres de clase deben estar separadas por punto y coma, y debe ser calificada en su totalidad. Los mensajes especiales y el administrador de servicio están siempre activos y no es necesario especificar esta opción. Si esta opción no se da, por defecto la movilidad y los servicios de eventos de notificación se inician.La siguiente tabla muestra los servicios disponibles con la distribución estándar de JADE. Más servicios (por ejemplo, el apoyo a la seguridad y la persistencia del agente están disponibles como addons)

Nombre

Clase de los Service

Messaging

jade.core.messaging.MessagingService

AgentManagement

jade.core.management.AgentManagementService

AgentMobility

jade.core.mobility.AgentMobilityService

Notification

jade.core.event.NotificationService

PersistentDelivery

jade.core.messaging.PersistentDeliveryService

MainReplication

jade.core.replication.MainReplicationService

AddressNotification

jade.core.replication.AddressNotificationService

Características ACL message exchange and MTP management. Activated automatically Basic management of agent lifecycle. Container and platform shutdown. RMA support. Activated automatically Agent mobility support. Active by default Support for platformlevel event system notifications. This is required to support the Sniffer and Introspector tools (see 6.4and 6.5). Active by default Allows buffering and persistent storage for undelivered ACL messages (see 5 for details). Inactive by default Support for replicating the Main Container for fault tolerance purposes. Has to be activated on each node hosting a Main Container (see 4 for details). Inactive by default Support for being notified

UDP Node Monitoring

Jade.core.nodeMonitoring.UDPNodeMonitoringServ ice

Fault Recovery

jade.core.faultRecovery.FaultRecoveryService

Topic Management

jade.core.messaging.TopicManagementService

Back-End Management

ade.imtp.leap.nio.BEManagementService

whenever the list of active Main Container copies changes, i.e. a new copy is added or an existing copy terminates (see 4 for details). Inactive by default Support for monitoring of platform nodes by means of UDP packets (see 2.3.7 for details) Inactive by default Support for recovering after a Main Container crash (typically used alternatively to the MainReplicationService to achieve Main Container fault tolerance) Inactive by default Support sending messages about a given topic. Such messages will be received by all agents that have previously registered to that topic Inactive by default Support for acting as mediator for split-containers. Inactive by default

-mtps: Especifica una lista de protocolos de transporte de mensajes externos para ser activados en el contenedor/container (de forma predeterminada el HTTP MTP esta activada en el contenedor principal/main-container y no se encuentra activado el MTP en otros contenedores)

-nomtp: Tiene prioridad sobre –mtps y lo reemplaza. Debe ser usado para reemplazar el comportamiento predeterminado del main-container (por defecto la opción –nomtp esta deseleccionada) -backupmain: especifica que esta instancia de JADE es un main-container de copia de seguridad y, como tal, que debe unirse a un contenedor principal (por defecto esta opción no está seleccionada) -smhost: Cuando una copia main-container esta iniciada, esta opcion debe ser utilizada para seleccionar el nombre de host en el Administrador de servicios que se va a exporter (por lo general es el local host). Esta opción solo es útil en los nodos donde el servicio Main-Replication se encuentre activa. -smport: Cuando una copia main-container esta iniciada, esta opción debe ser utilizada para seleccionar el puerto TCP en el administrador de servicios que se va exportar (por lo general es el local host). Esta opción solo es útil en los nodos donde el servicio Main-Replication se encuentre activa. -smaddrs: cuando múltiples copias del main-container están activadas en la plataforma, un contenedor periférico se conecta a la que apunta el par de opciones. Con esta opción, las direcciones de todas las demás copias se pueden enumerar, por lo que el contenedor es capaz de volver a conectar con otra copia si el actual no está disponible. Esta opción es una alternativa de activar el servicio de Address-Notification, en lugar de establecer un protocolo de actualización, simplemente proporciona una lista fija de direcciones conocidas de copias del mainconteiner. -aclcodecs: Por defecto todos los mensajes entregados a los agentes que viven en plataformas remotas son codificadas por la cadena base ACLCodec. Esta opción permite especificar una lista adicional ACLCodec que estará a disposición de los agentes del contenedor puesto en marcha con el fin de codificar / descodificar mensajes. Con el fin de utilizar agentes codecs se tiene que establecer un valor en el campo aclRepresentation de la sobbre los enviados / recibidos ACLMessages. Mirar las especificaciones FIPA para los nombres estándar de estos códecs. -nomobility: Desactiva la movilidad y el apoyo de clonación en el contenedor de lanzamiento. De esta manera, el contenedor no aceptará las solicitudes de migración de agentes o la clonación agente, opción que podría ser útil para mejorar el nivel de seguridad para el host en este contenedor se está ejecutando. Tenga en cuenta que la plataforma puede incluir tanto los contenedores donde la movilidad está habilitada y contenedores donde se desactiva. Por defecto esta opción no está seleccionada. -version: Imprime la versión de la plataforma JADE. -help: Imprime información básica sobre los comandos. -conf: Especifica una propiedad del archivo. Todas las opciones especificadas en dicho archivo se utilizan para lanzar JADE. Ejemplos de ejecución de línea de comandos: Ejecucion de la plataforma jade con un puerto asignado “801”: java jade.Boot –local-port 801

Ejecucion del gui con un puerto asignado: java jade.Boot –local-port 801 -gui

Ejecucion de un agente en la plataforma jade sin iniciar el gui: java jade.Boot –local-port 801 mi_nombre:miclase(argumento1,argumento2) java jade.Boot –local-port 801 mi_nombre:mipaquete.miclase(argumento1,argumento2)

5. Ejecución remota JADE es una plataforma que permite la ejecución de un sistema de agentes en el que éstos puedan estar repartidos entre diversos hosts. Para ejecutar un agente en remoto tendríamos que ejecutar la orden java jade.Boot -container -host nombreHost : desde la línea de comandos. También es posible crear un RMA que ponga en contacto la plataforma local con la remota. Esto significa que desde el RMA de ambas plataformas podremos contemplar los cambios producidos en el sistema de agentes, e interactuar con dichos agentes. Para ello tenemos que ejecutar la orden java jade.Boot -container -host nombreHost RMA1:jade.tools.rma.rma desde la línea de comandos.

5.1.Adherir una plataforma Para adherir una plataforma existen dos formas IIOP y HTTP para mayor información entrar a la siguiente página http://jade.tilab.com/doc/tutorials/JADEAdmin/HttpMtpTutorial.html 

Por el protocolo IIOP

Por consola ejecutamos el cmd de Windows Escribimos java jade.Boot –gui –mtp jade.mtp.iiop.MessageTransportProtocol Se crearan los archivos de texto MTPs-Main-Container.txt, APDescription.txt; el que nos interesa es el primero que tendrá una información similar: IOR:000000000000001149444C3A464950412F4D54533A312E30000000000000000100000000000 0006E000102000000000D3139322E3136382E312E33330000130800000019AFABCB00000000024 CF6BEDC000000080000000000000000140000000000000200000001000000200000000000010001 00000002050100010001002000010109000000010001010000000026000000020002 Una vez hecho esto copiamos todo el contenido del archivo MTPs-Main-Container.txt nos vamos a gui, le damos click RemotePlatforms luego AddPlataform via AMS AID

Le damos click RemotePlatforms luego AddPlataform via AMS AID

Figura 9

Name: ams@frodo:1099/jade Click derecho en Addresses y luego click en Add colocar IOR:000000000000001149444C3A464950412F4D54533A312E3 00000000000000001000000000000006E000102000000000D3 139322E3136382E312E33330000130800000019AFABCB00000 000024CF6BEDC0000000800000000000000001400000000000 00200000001000000200000000000010001000000020501000 10001002000010109000000010001010000000026000000020 002 El gui o RMA mostrara la siguiente imagen la cual solo nos muestra los gentes de la otra plataforma Nota: No se visualizan los contenedores y tampoco podemos Figura 10 manejar los agentes (suspender, eliminar y crear) solo podemos enviar mensajes para esto último no es necesario agregar una plataforma al RMA se explicara más adelante lo de la comunicación. Nota: Se crean en el directorio donde se ejecuta ejemplo si lo ejecutaran en este directorio

C:\Documents and Settings\jose> java jade.Boot –gui –mtp jade.mtp.iiop.MessageTransportProtocol Los archives se localizarían en C:\Documents and Settings\jose 

Por el protocolo HTTP en una LAN

Le damos click RemotePlatforms luego AddPlataform via AMS AID

Figura 11

Name: ams@frodo:1099/jade Click derecho en Addresses y luego click en Add colocar http://Frodo:7778/acc nos mostrara en el gui o RMA la siguiente imagen la cual solo nos muestra los gentes de la otra plataforma

Figura 12

Nota: No se visualizan los contenedores y tampoco podemos manejar los agentes (suspender, eliminar y crear) solo podemos enviar mensajes para esto último no es necesario agregar una plataforma al RMA se explicara más adelante lo de la comunicación.

Figura 13



Jade, Lans y routers

Solo se cambia el nombre de la plataforma por la ISP ejemplo 65.95.65.3 sería así: Name: [email protected]:1099/jade Addresses: http://65.95.65.3:7778/acc

6. Programar agentes en JADE Programar un agente JADE consiste en: Definir una clase Java que representa al agente (la cual debe heredar de la clase jade.core.Agent). Implementar los comportamientos que va a manifestar. Un agente JADE cumple las siguientes características: Tiene un nombre único en el entorno de ejecución. Se implementa como un único hilo de ejecución (single-threaded). Tiene un método de inicio (setup) y otro de fin (takeDown). (Ver Figura 12)

El método protegido setup() sirve para inicializar el agente incluyendo instrucciones que especificarán la ontología a utilizar y los comportamientos asociados al agente. Se invoca al comenzar la ejecución del agente. El método protegido takeDown() sirve para liberar recursos antes de la eliminación del agente. Este método es invocado cuando se realiza una llamada al método doDelete(), que es el que realmente da por finalizada la ejecución del agente. Ambos métodos deben ser sobrescritos. En su implementación se define una clase interna por cada uno de los comportamientos asociados al agente. Estos comportamientos se utilizan básicamente para el envío y recepción de mensajes, aunque también se pueden utilizar para realizar otras tareas. La clase Agent: Es una superclase común que permite a los usuarios crear software de agentes. Suministra métodos que permiten ejecutar las tareas básicas de los agentes como: Pasar mensajes utilizando objetos ACLMessage, con correspondencia de patrones. Dar soporte al ciclo de vida de un agente. Planificar y ejecutar múltiples actividades concurrentemente. Los programadores de aplicaciones basadas en agentes deben escribir sus propios agentes como subclases Agent, añadiendo tantos comportamientos específicos como sean necesarios y explotando las capacidades de la clase Agent.

6.1.Ciclo de vida de un agente Un agente está sujeto a un ciclo de vida en el que se definen los estados en los cuales se puede encontrar el agente, así como los cambios que se pueden realizar entre los diferentes estados. El ciclo de vida de un agente JADE sigue el ciclo propuesto por FIPA, es decir, cumple con la propuesta del estándar de interoperabilidad entre agentes más aceptado.

6.2.Estados de un agente Un agente puede estar en los siguientes estados: Iniciado: El objeto Agente está creado pero todavía no se ha registrado en el AMS, no tiene nombre ni dirección y tampoco se puede comunicar con otros agentes. Activo: El Agente está registrado en el AMS, tiene un nombre, una dirección y puede acceder a todas las opciones de JADE. Suspendido: El Agente está parado. Su hilo de ejecución está detenido y no ejecuta ningún Comportamiento. En espera: El Agente está bloqueado esperando por algo. Su hilo de ejecución está dormido en un monitor de java y se despertará cuando se cumpla una cierta condición (cuando reciba un mensaje).

Desconocido: El Agente ha sido eliminado. El hilo de ejecución ha terminado y se ha eliminado del registro del AMS. Tránsito: Un Agente móvil entra en este estado mientras está migrando a una nueva localización. El sistema sigue guardando los mensajes en el buffer hasta que el agente vuelve a estar activo.

6.3.Transiciones entre estados: Un agente puede cambiar de un estado a otro a través de transiciones. Estas transiciones pueden ser ejecutadas a través de métodos disponibles en la clase Agent y ser capturados por métodos que se pueden sobrescribir. Para saber en qué estado se encuentra un agente se puede usar el método getAgentState( ) de la clase Agent que devuelve un objeto de la clase AgentState public AgentState getAgentState()

Acción

Descripción

Método que Método que realiza la acción captura la acción

Crear

Creación o instalación de un nuevo agente.

Constructor

Invocar

Invocación de un nuevo agente.

Suspender

Pone un agente en estado suspendido. Puede doSuspend() ser iniciado por el agente o por el AMS.

setup()

Continúa con la ejecución de un agente que se Reanudar encuentra en estado suspendido. Sólo puede ser iniciado por el AMS. Esperar

Pone un agente en estado de espera. Sólo doWait() puede ser iniciado por el agente.

Continúa con la ejecución de un agente que se Despertar encuentra en estado de espera. Sólo puede ser doWake() iniciado por el AMS. Mover

Pone un agente en otro contenedor cambiando su estado al de tránsito. Sólo puede ser iniciado doMove() por el agente.

Ejecutar

Continúa con la ejecución de un agente que se encuentra en estado de tránsito. Sólo puede ser iniciado por el AMS.

Destruir

La terminación UNMSMl o forzosa de un agente. Sólo puede ser iniciado por el AMS y no doDelete() puede ser ignorado por el agente.

beforeMove() afterMove()

takeDown()

y

Visión gráfica

Figura 14

Flujo de control de un agente La Figura 15 muestra el flujo de vida de un agente básico. Como se ve todo comienza desde el método setup() el cual indica que el agente se encuentra vivo luego se ve si se ha invocado al método doDelete() el cual invoca al método takeDown() el cual termina con la vida del agente, si encaso no es invocado pasa a realizar una serie de actividades hasta encontrarse con su primer

comportamiento a ejecutar, el cual inicia la acción en el método action() hasta finalizarlo si esto sucede se ejecuta el método done() de este comportamiento para determinar si se ha terminado correctamente.

Figura 15

7. Programación de Agentes Jade Aquí se muestra el esqueleto de un agente el cual consta de de un método setup() en el cual inicia el agente al crearse y takeDown()se invoca cuando se elimina o mata al agente si se invoca con el método doDelete()del AID se esplicara mas adelante como usarlo.

import jade.core.Agent; public class MiAgente extends Agent { protected void setup(){ // Inicialización del agente MiAgente System.out.println(“Agente Iniciado”); } protected void takeDown() { // Liberación de recursos del agente System.out.println(“Agente finalizado”); } }

7.1.Ejemplo de ejecución de agentes JADE mediante la consola de comando: Se guarda el Archivo con el nombre MiAgente.Java luego se abre el cmd. Se compila el archivo Javac MiAgente.Java. (ver capitulo 2.3) Se crea al agente Ejemplo y Ejemplo2 sin paso de argumentos ambos tienen la misma clase Agente, pueden ser distintas. Java jade.Boot –port 1099 Ejemplo:MiAgente; Ejemplo2:MiAgente Se crea al agente Ejemplo y Ejemplo2 con paso de argumentos las comas separan los argumentos. Java jade.Boot –port 1099 Ejemplo:MiAgente(Hola,help); Ejemplo2: MiAgente(hola2,help2)

NOTA: los comandos anteriores solo funcionan si es que la plataforma jade no ha sido levantada, si es levantada previamente será necesario agregar –container antes del –port solo si el puerto es diferente al 1099, sino no es necesario. Ejemplo de código de un Agente al cual se le pasa argumentos y los muestra en pantalla. import jade.core.Agent; import java.util.Iterator; public class AgenteHolaMundo extends Agent { protected void setup(){ // Imprime un mensaje de bienvenida System.out.println("Mi nombre local es: "+getAID().getLocalName()); System.out.println("Mi GUID es: "+ getAID().getName()); System.out.println("Mis direcciones son:"); Iterator it = getAID().getAllAddresses(); while(it.hasNext()){ System.out.println("- "+it.next()); }

//pasando argumentos System.out.println("Mis argumentos son:"); Object[] args = getArguments(); if(args != null){ for(int i=0; i7); } }//fin de la clase del comportamiento }//fin de la clase del agente

10.2.3. Método block(): Los comportamientos también pueden ser bloqueados utilizando el método block(). Este método permite bloquear un comportamiento hasta que se realice una acción por lo general el envió o recepción de un mensaje. Este método no afecta a los otros comportamientos del agente. Cuando el método action() finaliza el método block() coloca el comportamiento en la cola de comportamientos. Un comportamiento puede ser bloqueado durante un tiempo determinado expresado en milisegundos, pasando el valor al método block(). Este método no puede verse como el método sleep() de los Threads, ya que este no para la ejecucion sino que espera que el método action() finalice. Una vez finalizado, si el comportamiento no termina, este pasa a la lista de comportamientos bloqueados durante el tiempo que se indique en este o hasta que reciba un evento o mensaje. import jade.core.Agent; import jade.core.behaviours.*; public class Agente_Block extends Agent{ protected void setup() { // Añadiendo el Comportamiento addBehaviour(new Micomportamiento()); } protected void takeDown(){ System.out.println(“Adios mundo”); } //Definiendo el comportamiento private class Micomportamiento extends Behaviour{ int n=1; public void action(){ System.out.println(“número de ejecuciones: ”+n); //bloqueamos durante un segundo block(1000); System.out.println(“después de 1000 milisegundos”); n++; } public boolean done(){ if(n>7) myAgent.doDelete(); return(n>7); }

}//fin de la clase del comportamiento }//fin de la clase del agente

10.2.4. Método blockReceive(): Este método se comporta similar al método block(), con la diferencia que este detiene todos los comportamientos del agente, además devuelve el mensaje recibido que libero el bloqueo. Su uso seda al momento de la recepción de mensajes en algún comportamiento. ACLMessage mensaje = blockingReceive();

Un comportamiento puede ser desbloqueado cuando se da alguna de estas condiciones: 

 

Cuando el agente asociado al comportamiento recibe un mensaje ACL. Cuando sucede este caso el comportamiento se saca de la cola de comportamientos bloqueados y se coloca en la cola de comportamientos activos. Al llegar un mensaje, todos los comportamientos de la cola de bloqueados verifican si es para ellos o no; en caso de no pertenecer al comportamiento este debe volver a bloquearse. Cuando el tiempo de bloqueo expira, es colocado en la cola de activos. Cuando es llamado el método restar() por el comportamiento, este lo desbloquea automáticamente y lo coloca en la cola de activos.

10.2.5. Métodos onStart() y onEnd(): La clase Behaviour brinda dos métodos opcionales al action() y al done(), los cuales son onStart() y onEnd(). Estos métodos pueden ser sobrescritos por los programadores para realizar operaciones anteriores o posteriores al método action(). Además estos métodos se implementan solo una vez.  Método onStart() se ejecuta antes al método action().  Método onEnd() se ejecuta antes de finalizar el comportamiento (se ejecuta después de que el método done() devuelva true) además devuelve un entero que determina la finalización del comportamiento. Este valor es determinado por el programador de acuerdo a las condiciones que se implementen. El método onEnd() es ejecutado cuando el comportamiento ya ha sido eliminado de la cola de comportamientos es decir cuando ya el comportamiento se ha completado. Si el método reset() es llamado dentro de este no podrá reiniciarse este comportamiento y además se debe volver añadir de nuevo el comportamiento al agente. Este ejemplo muestra como se debe realizar lo mencionado anteriormente. import jade.core.Agent; import jade.core.behaviours.*;

public class Agente_Start_End extends Agent{ protected void setup() { // Añadiendo el Comportamiento addBehaviour(new Micomportamiento()); } protected void takeDown(){ System.out.println(“Adios mundo”); } //Definiendo el comportamiento private class Micomportamiento extends Behaviour{ public void onStart(){ System.out.println(“la primera ejecucion justo antes del action()”); } public void action(){ System.out.println(“Ejecucion del método action()”); } public boolean done(){ return true; } //Hacemos que el comportamiento se reinicie al finalizar Public int onEnd(){ System.out.println(“Ejecucion del método onEnd() que se realiza al momento de completar el comportamiento”); reset(); myAgent.addBehaviour(this); return 0; } }//fin de la clase del comportamiento }//fin de la clase del agente

10.3.

Ejecución de los comportamientos

Cada agente posee un planificador o scheduler de comportamientos. Esta multitarea se realiza de forma preemptiva para todos los comportamientos que se encuentren en la cola de activos, lo que significa que ningún comportamiento puede ser interrumpido hasta que este finalice (se da cuando finaliza el método action()). Los comportamientos son parecidos a los threads, sin embargo no son ejecutados en forma concurrente, la forma de su ejecucion lo define el programador a diferencia de los threads de JAVA que la decisión de ser ejecutados es tomada por la maquina virtual. En un agente pueden estar activos varios comportamientos a la vez pero se ejecuta un único thread, con el fin de ahorrar ciclos de CPU y la memoria que esto implica. El funcionamiento de los comportamientos esta implementado a 2 niveles.

 

Una cola circular de activos. Una cola de bloqueados.

Figura 9. Funcionamiento de un comportamiento.

11.

Java Server Faces (JSF)

El objetivo de la tecnología JavaServer Faces es desarrollar aplicaciones web de forma parecida a como se construyen aplicaciones locales con Java Swing, AWT (Abstract Window Toolkit), SWT (Standard Widget Toolkit) o cualquier otra API similar. Tradicionalmente, las aplicaciones web se han codificado mediante páginas JSP (Java Server Pages) que recibían peticiones a través de formularios y construían como respuesta páginas HTML (Hiper Text Markup Language) mediante ejecución directa o indirecta -a través de bibliotecas de etiquetas- de código Java, lo que permitía, por ejemplo, acceder a bases de datos para obtener los resultados a mostrar amén de realizar operaciones marginales como insertar o modificar registros en tablas relacionales, actualizar un carrito de la compra, etc. JavaServer Faces pretende facilitar la construcción de estas aplicaciones proporcionando un entorno de trabajo (framework) vía web que gestiona las acciones producidas por el usuario en su

página HTML y las traduce a eventos que son enviados al servidor con el objetivo de regenerar la página original y reflejar los cambios pertinentes provocados por dichas acciones. En definitivas cuentas, se trata de hacer aplicaciones Java en las que el cliente no es una ventana de la clase JFrame o similar, sino una página HTML. Como el lector puede imaginar, cualquier evento realizado sobre una página JSF incurre en una carga sobre la red, ya que el evento debe enviarse a través de ésta al servidor, y la respuesta de éste debe devolverse al cliente; por ello, el diseño de aplicaciones JavaServer Faces debe hacerse con cuidado cuando se pretenda poner las aplicaciones a disposición del mundo entero a través de internet. Aquellas aplicaciones que vayan a ser utilizadas en una intranet podrán aprovecharse de un mayor ancho de banda y producirán una respuesta mucho más rápida. 

Características principales

La tecnología JavaServer Faces constituye un marco de trabajo (framework) de interfaces de usuario del lado de servidor para aplicaciones web basadas en tecnología Java y en el patrón MVC (Modelo Vista Controlador). Los principales componentes de la tecnología JavaServer Faces son:       

Una API y una implementación de referencia para: Representar componentes de interfaz de usuario (UI-User Interface) y manejar su estado Manejar eventos, validar en el lado del servidor y convertir datos Definir la navegación entre páginas Soportar internacionalización y accesibilidad, y Proporcionar extensibilidad para todas estas características. Una librería de etiquetas JavaServer Pages (JSP) personalizadas para dibujar componentes UI dentro de una página JSP.

Este modelo de programación bien definido y la librería de etiquetas para componentes UI facilita de forma significativa la tarea de la construcción y mantenimiento de aplicaciones web con UIs en el lado servidor. Con un mínimo esfuerzo, es posible:   

Conectar eventos generados en el cliente a código de la aplicación en el lado servidor. Mapear componentes UI a una página de datos en el lado servidor. Construir una interfaz de usuario con componentes reutilizables y extensibles.

Como se puede apreciar en la Figura 16, la interfaz de usuario que se crea con la tecnología JavaServer Faces (representada por miUI en el gráfico) se ejecuta en el servidor y se renderiza en el cliente.

Figura 16 Diagrama de una aplicación JSF

En la figura no queda qué es físicamente miUI. La página JSP, miform.jsp, especifica los componentes de la interfaz de usuario mediante etiquetas personalizadas definidas por la tecnología JavaServer Faces. LA UI de la aplicación web (representada por miUI en la figura) maneja los objetos referenciados por la JSP, que pueden ser de los siguientes tipos:   

Objetos componentes que mapean las etiquetas sobre la página JSP. Oyentes de eventos, validadores y conversores registrados y asociados a los componentes. Objetos del modelo que encapsulan los datos y las funcionalidades de los componentes específicos de la aplicación (lógica de negocio).

11.1. Ejemplos de paginas JSF A. La siguiente pagina muestra una entrada de texto a la cual se le ingresa cualquier texto y lo pinta en la parte inferior luego de dar enter en el cuadro de texto.

Figura 17

Facelet Title

B. En esta página se agrega un botón el cual te dirige a otra página que solo muestra el contenido que se escribió en el cuadro de texto. Pagina ejemplo1.xhtml

Figura 18 Facelet Title

Pagina ejemplo2.xhtml Muestra el contenido de lo que se escriba en la página anterior

Facelet Title

11.2. Estructura de una aplicación JSF Las aplicaciones JSF siguen un estándar de creación en la estructura de sus directorios, los cuales se comprimen en un archivo war para su portabilidad. Esta estructura de directorio estándar es: Aplicación/ Ficheros XHTML WEB-INF/ Archivos de configuración Clases/ Archivos .class Lib/ Librerías La estructura del archivo WAR queda así: ejemploBasico.war index.xhtml ejemplo1.xhtml ejemplo2.xhtml META-INF/ MANIFEST.MF WEB-INF web.xml classes/ modelo/ Model1.class controlador/ ControlEjem.class lib/ jsf-api.jar jsf-impl.jar …

11.3. Patrón MVC Como se explico antes JSF te obliga de cierta manera a programar bajo el patrón MVC (modelo, vista, controlador).   

Donde el modelo es la representación de los datos que manipulara el aplicativo. La vista contiene las pantallas (xhtml) a mostrar a los usuarios. El controlador maneja los eventos de pantalla, entre otras cosas.

Las paginas anteriores existe un conjunto de caracteres “#{}” sirven de nexo con los archivos java que pertenecen a la capa controlador. Antiguamente existía un archivo faces-config.xml pero actualmente se usa solo las anotaciones que está precedida del carácter arroba @. La capa controlador interactúa con la del modelo para crear los objetos los cuales son rellenados desde la página. A continuación se muestra las clases de las capas controlador y modelo para el ejemplo anterior. Capa Controlador: ControlEjm.java package controlador; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import modelo.Model1; /** * @author UMSM */ @ManagedBean @RequestScoped public class ControlEjem { private Model1 model1 ; /** * Creates a new instance of ControlEjem */ public ControlEjem () { model1 = new Model1(); } public Model1 getModel1() { return model1; } public void setModel1(Model1 model1) { this.model1 = model1; } }

Capa Modelo: Model1.java package modelo; // Generated 22/11/2012 07:02:08 AM by Hibernate Tools 3.2.1.GA public class Model1 implements java.io.Serializable { private String nm; public Model1 () { } public Model1 (String nm) { this.nm = nm; } public String getNm() { return this.nm; } public void setNm(String nm) { this.nm = nm; } }

12.

Hibernate

Hibernate es un marco de trabajo para persistencia de datos (en java). En la mayoría de las aplicaciones empresariales, si no es que en todas, una parte muy importante es el almacenamiento de datos de forma que estos datos puedan sobrevivir más allá del tiempo que nuestra aplicación está encendida (ya sea en una aplicación standalone o en una aplicación web). El almacén de datos más común son las bases de datos relacionales. La naturaleza de estas bases hace que no sea tan fácil usarlas en el almacenamiento de datos en aplicaciones orientadas a objetos (por las diferencias entre el modelo de datos de objetos y el modelo de datos relacionales), ya que para guardar un objeto debemos extraer cada una de sus propiedades que queremos persistir y armar con ellos una sentencia INSERT de SQL. De la misma forma, cuando queremos recuperar los datos de un objeto, debemos usar una sentencia SELECT de SQL y después extraer el valor de cada una de las columnas recuperadas y llenar así nuestro objeto. Esto puede no parecer un problema en aplicaciones pequeñas, pero cuando comenzamos a tener muchos objetos que debemos guardar se vuelve algo muy pesado y engorroso, además de que consume mucho de nuestro tiempo que podríamos dedicar a mejorar la lógica de la aplicación, o a realizar pruebas de la misma. Esto se hizo de esta manera durante muchos años, hasta que comenzaron a surgir las soluciones de Mapeo Objeto/Relacional (ORM por sus siglas en inglés). El mapeo objeto/relacional se refiere

a una técnica de mapear representaciones de datos de un modelo de objetos a un modelo de datos relacionales con un esquema basado en SQL. Hibernate, como la definen sus autores, es una herramienta de mapeo objeto/relacional para ambientes Java. Además no solo se encarga del mapeo de clases Java a tablas de la base de datos (y de regreso), sino que también maneja los queries y recuperación de datos, lo que puede reducir de forma significativa el tiempo de desarrollo que de otra forma gastaríamos manejando los datos de forma manual con SQL y JDBC, encargándose de esta forma de alrededor del 95% de las tareas comunes relacionadas con la persistencia de datos, manejando todos los problemas relativos con la base de datos particular con la que estemos trabajando, de forma transparente para nosotros como desarrolladores. Entonces, si cambiamos el manejador de base de datos no será necesario que modifiquemos todo el SQL que ya teníamos para adaptarse al SQL que maneja la nueva base de datos. Solo será necesario modificar una línea en un archivo de configuración de Hibernate, y este se encargará del resto. Existen dos formas de hacer los mapeos en Hibernate, la primera es a través de archivos de mapeo en XML, que es la forma que veremos en este primer tutorial. La otra forma es usando anotaciones. Usaremos MySQL 5.1 como base de datos. También deben bajar el conector para Java versión 5.1.7. Creamos una base de datos llamada "pruebahibernate". No se preocupen por crear alguna tabla, ya que haremos que sea el propio Hibernate el que las genere. Ahora comencemos con nuestra aplicación. Lo primero que haremos es crear una biblioteca de NetBeans con los jars básicos de Hibernate, de esta forma cada vez que queramos usar Hibernate en un proyecto solo tendremos que agregar esta biblioteca. En realidad no crearemos esta biblioteca desde cero, ya que NetBeans ya tiene una biblioteca de Hibernate 3.2.5, solo actualizaremos la biblioteca con la última versión de Hibernate, la 3.3.1 GA. Así que descargamos la última versión del core de Hibernate desde la página de descarga de Hibernate. Una vez que descarguemos y descomprimamos el archivo correspondiente veremos que en la raíz hay dos jars de Hibernate: "hibernate3.jar" y "hibernate-testing.jar". "hibernate3.jar" contiene las clases principales para el uso de Hibernate. Existen varias clases de soporte que son usadas por Hibernate para su funcionamiento UNMSMl. Algunas son opcionales y otras son requeridas. Afortunadamente estas se encuentran separadas en el mismo archivo que hemos descargado. Las clases obligatorias, que son las que nos interesan en este caso, se encuentran en el directorio "lib\required". Bien, entonces para actualizar la biblioteca abrimos el NetBeans y nos dirigimos al menú "Tools -> Libraries":

En la ventana que se abre buscamos la biblioteca "Hibernate" y la seleccionamos. Con esto se mostrarán los archivos que la conforman. Seleccionamos todos los archivos y presionamos el botón "Remove" para eliminarlos de la biblioteca.

Una vez eliminados los archivos presionamos el botón "Add JAR/Folder..." para agregar los nuevos archivos:

Agregamos a la biblioteca los siguientes archivos: 

hibernate3.jar

y del directorio de jars requeridos:     

antlr-2.7.6.jar commons-collections-3.1.jar dom4j-1.6.1.jar javassist-3.4.GA.jar jta-1.1.jar

O sea, casi todos los archivos requeridos. Estamos excluyendo el archivo "slf4j-api-1.5.2.jar" porque si lo incluimos solo, se lanza una excepción. Lo que ocurre es que slf4j es una fachada para el logging, o bitácora de la aplicación. Esto significa que podemos usar el framework de logging que queramos (en teoría). Sin embargo en la distribución de Hibernate no se incluye ningún jar con una clase que implemente dicha fachada, por lo que debemos bajar uno nosotros mismos. Podemos hacer dos cosas, la primer es agregar el archivo "slf4j-api-1.5.2.jar" que viene con Hibernate a nuestra biblioteca y el zip con la versión correspontiente de slf4j. De él extraemos "slf4j-simple-1.5.2.jar" (o el archivo que se ajuste al framework de logging que estemos usando) y lo incluimos en la biblioteca. Lo otro que podemos hacer es, aprovechando que ya estamos bajando jars, descargar la última versión de slf4j de aquí (actualmente es la 1.5.6) y aprovechar para agregar los archivos "slf4j-api1.5.6.jar" y "slf4j-simple-1.5.6.jar" a nuestra biblioteca. Yo haré esto último. Una vez seleccionados estos archivos la biblioteca de Hibernate debe verse así:

Presionamos el botón "OK" y nuestra biblioteca ya estará actualizada. Ahora creamos un nuevo proyecto de NetBeans (menú "File -> New Project... -> Java -> Java Application"). Le damos un nombre y una ubicación al proyecto y nos aseguramos de que las opciones "Create Main Class" y "Set as Main Project" estén habilitadas. Presionamos el botón "Finish" y veremos aparecer en el editor nuestra clase "Main".

Agregamos la biblioteca de "Hibernate", que creamos hace unos momentos, a nuestro proyecto. Hacemos clic derecho en el nodo "Libraries" del proyecto. En el menú contextual que se abre seleccionamos la opción "Add Library...":

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

Presionamos el botón "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos también para agregar el conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

El siguiente paso es crear una clase cuyas instancias serán almacenadas como fila de una tabla en base de datos. Este tipo de objetos son llamados "Entidades". Para este ejemplo crearemos una pequeña y básica agenda, así que las entidades serán objetos de la clase "Contacto". Los atributos que tendrá esta serán un nombre, un correo, y un número telefónico. Además, por regla, necesitamos un atributo que funcione como identificador para cada una de las entidades. En este caso he hecho que la clase implementa la interface "java.io.Serializable", esto no es obligatorio pero es una buena práctica. La clase "Contacto" queda de la siguiente forma: public class Contacto implements Serializable { private long id; private String nombre; private String email; private String telefono; public Contacto() { } public Contacto(String nombre, String email, String telefono) { this.nombre = nombre; this.email = email; this.telefono = telefono; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public long getId() { return id; } private void setId(long id) { this.id = id; } public String getNombre() { return nombre; } public void setNombre(String nombre) {

this.nombre = nombre; } public String getTelefono() { return telefono; } public void setTelefono(String telefono) { this.telefono = telefono; } }

La clase "Contacto" usa la convención de nombres JavaBeans para los getters y setters y visibilidad privada para los atributos. Este también es un diseño recomendado pero no obligatorio. Hibernate puede acceder a los campos o atributos de las entidades directamente. El constructor sin argumentos si es obligatorio ya que Hibernate creará instancias de esta clase usando reflexión cuando recupere las entidades de la base de datos. Este constructor puede ser privado (si es que no quieren permitir que alguien más lo utilice), pero usualmente el nivel de acceso más restrictivo que usaremos es el de paquete (el default), ya que esto hace más eficiente la creación de los objetos. La propiedad "id" mantendrá, como dije antes, un valor único que identificará a cada una de las instancias de "Contacto". Todas las clases de entidades persistentes deben tener una propiedad que sirva como identificador si queremos usar el conjunto completo de funcionalidades que nos ofrece Hibernate (y que veremos a lo largo de esta serie de tutoriales). De todas formas, la mayoría de las aplicaciones necesitan poder distinguir objetos de la misma clase mediante algún tipo de identificador. Usualmente no manipulamos directamente este identificador (dejamos que sea la base de datos quien lo genere, cuando la entidad sea guardada, y Hibernate quien lo asigne al objeto), por lo tanto el setter del "id" es privado (fíjense cómo lo he puesto en la clase "Contacto"). Hibernate puede acceder a los campos private directamente, así que no debemos preocuparnos por el hecho de que el identificador no pudiera ser establecido. El siguiente paso es crear el archivo de mapeo. Si recuerdan, anteriormente dije que Hibernate es una herramienta de mapeos Objeto/Relacional, o sea que mapea los atributos de los objetos con las columnas de una tabla de una base de datos relacional. También dije que hay dos formas de hacerlo: mediante un archivo de mapeo en XML y mediante anotaciones y que en esta ocasión veríamos solo como usar los archivos de mapeo. Crearemos un nuevo paquete que contendrá los archivos de mapeo, no es obligatorio tener los archivos de mapeo en un paquete separado ya que más adelante indicaremos donde se encuentra cada uno de los archivos, pero nos ayudará a mantener un poco de orden en nuestro proyecto. Hacemos clic derecho sobre el nodo "Source Packages" del proyecto para mostrar un menú contextual. De ese menú seleccionamos la opción "New -> Java Package..":

Nombramos a este paquete como "mapeos" y presionamos el botón "Finish" para agregar el nuevo paquete. Ahora creamos un nuevo archivo XML que contendrá el mapeo de la clase "Contacto" con la tabla "CONTACTOS" de la base de datos. Por convención la extensión de estos archivos es ".hbm.xml" y tiene el mismo nombre de la entidad que está mapeando (aunque eso tampoco es necesario ya que podemos mapear más de una clase o entidad dentro del mismo archivo). Hacemos clic derecho sobre el paquete que acabamos de crear. En el menú contextual que se abre seleccionamos la opción "New -> XML Document". Si no se muestra está opción seleccionamos "Other..." y en la ventana que se abre seleccionamos "XML -> XML Document":

Le damos al archivo el nombre "Contacto.hbm" (el asistente se encargará de agregar de forma automática el ".xml" al final):

Presionamos el botón "Next >" y se nos preguntará qué tipo de documento queremos crear: solo un documento XML bien formado, un documento regido por un DTD, o un documento regido por un Schema XML. Aunque el documento de mapeo está regido por un DTD nosotros elegiremos crear un documento XML bien formado ("Well-formed Document") ya que es más fácil

simplemente pegarlo en el archivo que se creará que indicar mediante el asistente dónde se encuentra este archivo. Presionamos el botón "Finish" para que se nos muestre en el editor el nuevo archivo XML, el cual debe verse más o menos así:

Modificaremos este archivo. Eliminamos todo el contenido del archivo y lo reemplazamos por este:

Teniendo esta declaración, la cual indica el DTD que se usa para validar el archivo, el IDE nos ayudará a autocompletar las etiquetas y a asegurarnos que el archivo sea válido. El elemento "" es el nodo raíz del documento y, por lo tanto, el resto de los elementos irán entre estas dos etiquetas. El elemento con el que indicamos qué clase es la que estamos mapeando es el elemento "" este elemento tiene los atributos "name" y "table" que nos permiten indicar el nombre completo de la clase y la tabla con la que será mapeada, respectivamente:

Con esto indicamos que las entidades de la clase "Contacto" serán almacenadas en la tabla "CONTACTOS". Ahora debemos indicar cuál de los elementos de la clase entidad es el identificador. Este identificador será mapeado con la llave primaria de la tabla, además como nosotros no manejaremos el valor del identificador, le indicamos a Hibernate cómo queremos que este valor sea generado (la estrategia de generación). Para esto usamos el elemento "", indicando el nombre del atributo de la clase entidad que representa el identificador (que en este caso también se llama "id" ^-^). Opcionalmente en este elemento (como en el resto de los

elementos de mapeo de propiedades) podemos indicar con qué columna queremos que se mapee usando el atributo "column":

El elemento "" es el que nos permite indicar la estrategia de generación del identificador usando su atributo "class". Existen varias estrategias que están explicadas en esta página, pero las que usaremos más frecuentemente son "identity" (con la que Hibernate se encarga de generar el query necesario para que el nuevo identificador sea igual a el último identificador + 1) y "native" (con el que se usa la estrategia por default del manejador que estemos utilizando (dialecto)). Para terminar con el mapeo incluimos las declaraciones para el resto de las propiedades persistentes (las que queremos que sean almacenadas) de la clase entidad ("nombre", "email", y "telefono") usando el elemento "" en el cual indicamos el nombre de la propiedad como aparece en la clase entidad y, opcionalmente, el tipo de la propiedad y la columna con la que será mapeada usando los atributos "type" y "column" respectivamente:

El archivo "Contacto.hbm.xml" final debe verse así:

¿Qué ocurre si no indicamos el tipo de la propiedad? En ese caso Hibernate utiliza nuevamente reflexión en nuestra clase para determinar el tipo del atributo y así elegir el tipo más adecuado para la columna de la tabla (en caso de que dejemos que Hibernate genere las tablas).

¿Qué ocurre si no indicamos el nombre de la columna con la que mapea una propiedad? Esto depende de si Hibernate está generando las tablas de la base de datos o las hemos generado nosotros mismos. Si es Hibernate quien está generando las tablas no hay problema, simplemente dará a la columna correspondiente el mismos nombre de la propiedad. Por ejemplo, para la propiedad "email" creará una columna "email". Sin embargo, si nosotros hemos creado las tablas hay un riesgo potencial de un error. Hibernate buscará en las consultas una columna con el mismo nombre de la propiedad, pero si hemos usado un nombre distinto, por ejemplo en vez de "email" hemos llamado a la columna "E_MAIL" ocurrirá una excepción indicando que no se ha encontrado la columna "email", así que en ese caso debemos tener cuidado de indicar el nombre de las columnas como están en la base de datos. Bien, después de esta breve explicación podemos proseguir. Ya que hemos configurado el mapeo de nuestra clase entidad debemos configurar Hibernate. Hibernate está en la capa de nuestra aplicación que se conecta a la base de datos (la capa de persistencia), así que necesita información de la conexión. La conexión se hace a través de un pool de conexiones JDBC que también debemos configurar. La distribución de Hibernate contiene muchos pools de conexiones JDBC Open Source, como por ejemplo C3P0, pero en esta ocasión usaremos el pool de conexiones que Hibernate trae integrado. La configuración de Hibernate puede hacerse en tres lugares:   

Un archivo de propiedades llamado "hibernate.properties". Un archivo XML llamado "hibernate.cfg.xml". En código dentro de la misma aplicación.

En realidad los archivos pueden tener cualquier nombre, pero Hibernate buscará por default los archivos con los nombres que he mencionado, en una ubicación predeterminada (la raíz del classpath de la aplicación). Si queremos usar archivos con otros nombres deberemos especificarlo en el código. La mayoría, por lo que he podido ver en Internet, preferimos usar el archivo XML ya que, entre otras cosas, los IDEs nos ayudan a su creación y configuración gracias a que está regido por un DTD. Así que crearemos este archivo en nuestro proyecto. Hacemos clic derecho en el nodo "Source Packages" del proyecto. En el menú contextual que se abre seleccionamos "New -> XML Document...":

Nombramos al archivo "hibernate.cfg", el IDE se encargará de colocarle la extensión ".xml". Ubicamos el archivo en el directorio "src":

Con esto lograremos que el archivo quede en la raíz del classpath de la aplicación, también conocido como el paquete default. Presionamos el botón "Next >" y en la pantalla siguiente indicamos que queremos crear un documento XML bien formado (como en el caso anterior). Presionamos el botón "Finish " para generar el archivo. Si nos fijamos en el archivo generado, este debe encontrarse en un paquete llamado "":

Borramos todo el contenido del archivo generado y colocamos las siguientes líneas:

El DTD nos ayudará para que el IDE autocomplete las etiquetas. Como podemos ver, el elemento raíz del archivo de configuración es "" y, por lo tanto, todos los elementos los colocaremos entre estas dos etiquetas. Lo primero que debemos hacer es configurar un "session-factory", que básicamente es lo que le dice a Hibernate cómo conectarse y manejar la conexión a la base de datos. Podemos tener más de un "session-factory" en el archivo de configuración (por si quisiéramos conectarnos a más de una base de datos), pero por lo regular solo ponemos uno:



Lo siguiente es configurar la conexión a nuestra base de datos. En este archivo se configuran los parámetros básicos y típicos para una conexión (la URL, nombre de usuario, contraseña, driver, etc.). Cada uno de estos parámetros se configura dentro de una etiqueta "" (al igual que casi todos los elementos del archivo de configuración). Como dije antes, usaré una base de datos MySQL para este ejemplo, así que mi configuración queda de la siguiente forma: com.mysql.jdbc.Driver jdbc:mysql://localhost/pruebahibernate usuario password

Después, configuramos el pool de conexiones de Hibernate. En este caso como es un ejemplo muy simple, solo nos interesa tener una conexión en el pool, por lo que colocamos la propiedad "connection.pool_size" con un valor de "1": 1 El siguiente paso es muy importante. Debemos indicar el "dialecto" que usará Hibernate para comunicarse con la base de datos. Este dialecto es la variante de SQL que usa la base de datos para ejecutar queries. Indicamos el dialecto con el fully qualified class name, o el nombre completo de la clase incluyendo el paquete. En el caso de MySQL 5 usamos "org.hibernate.dialect.MySQL5Dialect". En esta página pueden encontrar una lista más o menos completa de los dialectos soportados por Hibernate, pero siempre es mejor revisar la documentación de la versión que estén usando para estar seguros: org.hibernate.dialect.MySQL5Dialect Otras dos propiedades importantes que podemos configurar son: "show_sql" que indica si queremos que las consultas SQL generadas sean mostradas en el stdout (UNMSMlmente la consola), y "hbm2ddl.auto", que indica si queremos que se genere automáticamente el esquema de la base de datos (las tablas). "show_sql" puede tomar valores de "true" o "false", yo lo colocaré en "true" (lo que puede ser bueno mientras estamos en etapas de desarrollo o pruebas, pero querrán cambiar su valor cuando su aplicación pase a producción). Por otro lado "hbm2ddl.auto" puede tomar los valores, segun la documentación oficial(falta "none"), de "validate", "update", "create", y "create-drop" (aunque no todos los valores funcionan para todas las bases de datos). Yo los colocaré de la siguiente forma: true create-drop

Con el valor "create-drop" hacemos que cada vez que se ejecute la aplicación Hibernate elimine las tablas de la base de datos y las vuelva a crear. Para terminar con este archivo de configuración, debemos indicar dónde se encuentra cada uno de los archivos de mapeo que hemos creado, usando el elemento "". En nuestro caso solo hemos creado un archivo de mapeo, pero debemos colocar un elemento "" por cada uno de los archivos que hayamos creado: En el elemento "resource" debemos colocar la ubicación de los archivos de mapeo dentro de la estructura de paquetes de la aplicación. El archivo de configuración "hibernate.cfg.xml" final debe verse así: com.mysql.jdbc.Driver jdbc:mysql://localhost/pruebahibernate usuario password 1 org.hibernate.dialect.MySQL5Dialect true create-drop

Esta es toda la configuración que debemos hacer. Ahora veremos el código necesario para guardar y recuperar objetos "Contacto" de la base de datos.

Lo primero que haremos es crear una clase ayudante o de utilidad llamada "HibernateUtil", que se hará cargo de inicializar y hacer el acceso al "org.hibernate.SessionFactory" (el objeto encargado de gestionar las sesiones de conexión a la base de datos que configuramos en el archivo "hibernate.cfg.xml") más conveniente. Dentro de esta clase declaramos un atributo static de tipo "SessionFactory", así nos aseguraremos de que solo existe una instancia en la aplicación. Además lo declararemos como final para que la referencia no pueda ser cambiada después de que la hayamos asignado. private static final SessionFactory sessionFactory; Después usamos un bloque de inicialización estático para inicializar esta variable en el momento en el que la clase sea cargada en la JVM. Para realizar esta inicialización lo primero que se necesita es una instancia de la clase "org.hibernate.cfg.Configuration" que permite a la aplicación especificar las propiedades y documentos de mapeo que se usarán (es aquí donde indicamos todo si no queremos usar un archivo XML o de propiedades). Si usamos el método "configure()" que no recibe parámetros entonces Hibernate busca el archivo "hibernate.cfg.xml" que creamos anteriormente. Una vez que tenemos este objeto, entonces podemos inicializar la instancia de "SessionFactory" con su método "buildSessionFactory()". Además como este proceso puede lanzar "org.hibernate.HibernateException" (que extiende de "RuntimeException") la cachamos y lanzamos como un "ExceptionInInitializarError" (que es lo único que puede lanzarse desde un bloque de inicialización). El bloque de inicialización queda de la siguiente forma: static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException he) { System.err.println("Ocurrió un error en la inicialización de la SessionFactory: " + he); throw new ExceptionInInitializerError(he); } }

Finalmente creamos un método static llamado "getSessionFactory()" para recuperar la instancia de la "SessionFactory": public static SessionFactory getSessionFactory() { return sessionFactory; } La clase "HibernateUtil" queda de la siguiente forma: import org.hibernate.HibernateException; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil {

private static final SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException he) { System.err.println("Ocurrió un error en la inicialización de la SessionFactory: " + he); throw new ExceptionInInitializerError(he); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }

Bien ha llegado el momento, ahora escribiremos una clase DAO (no seguiremos el patrón al pie de la letra, es solo para mostrar cómo trabajar con Hibernate) que nos permitirá realizar operaciones de base de datos. Creamos una clase llamada "ContactosDAO" y agregamos dos atributos, uno llamado "sesion" de tipo "org.hibernate.Session", y otro llamado "tx" de tipo "org.hibernate.Transaction". private Session sesion; private Transaction tx; Estos atributos nos servirán para mantener la referencia a la sesión a base de datos, y a la transacción actual, respectivamente. Ahora agregaremos dos métodos de utilidad. El primero nos ayudará a iniciar una sesión y una transacción en la base de datos. Llamaremos a este método "iniciaOperacion", y la implementación es la siguiente: private void iniciaOperacion() throws HibernateException { sesion = HibernateUtil.getSessionFactory().openSession(); tx = sesion.beginTransaction(); }

En el método anterior obtenemos una referencia a "SessionFactory" usando nuestra clase de utilidad "HibernateUtil". Una vez que tenemos la "SessionFactory" creamos una conexión a la base

de datos e iniciamos una nueva sesión con el método "openSession()". Una vez teniendo la sesión iniciamos una nueva transacción y obtenemos una referencia a ella con "beginTransaction()". Ahora el segundo método de utilidad (llamado "manejaExcepcion") nos ayudará a manejar las cosas en caso de que ocurra una excepción. Si esto pasa queremos que la transacción que estamos ejecutando se deshaga y se relance la excepción (o podríamos lanzar una propia). Por lo que el método queda así: private void manejaExcepcion(HibernateException he) throws HibernateException { tx.rollback(); throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he); }

Ahora crearemos los métodos que nos permitirán realizar las tareas de persistencia de una entidad "Contacto", conocidas en lenguaje de base de datos como CRUD: guardarla, actualizarla, eliminarla, buscar un entidad "Contacto" y obtener todas los contactos que existen en la base de datos, así que comencemos. Afortunadamente Hibernate hace que esto sea fácil ya que proporciona métodos para cada una de estas tareas. Primero veamos como guardar un objeto "Contacto". Para esto Hibernate proporciona el método "save" en el objeto de tipo "org.hibernate.Session", que se encarga de generar el "INSERT" apropiado para la entidad que estamos tratando de guardar. El método "guardaContacto" queda de la siguiente forma: public long guardaContacto(Contacto contacto) { long id = 0; try { iniciaOperacion(); id = (Long)sesion.save(contacto); tx.commit(); }catch(HibernateException he) { manejaExcepcion(he); throw he; }finally { sesion.close(); } return id; }

Regresamos el "id" generado al guardar el "Contacto" solo por si queremos usarlo más adelante en el proceso (como lo haremos nosotros), o si queremos mostrarle al usuario, por alguna razón, el identificador del "Contacto". Ahora veremos cómo actualizar un "Contacto". Para eso usamos el método "update" del objeto "sesion" en nuestro método "actualizaContacto":

public void actualizaContacto(Contacto contacto) throws HibernateException { try { iniciaOperacion(); sesion.update(contacto); tx.commit(); }catch (HibernateException he) { manejaExcepcion(he); throw he; }finally { sesion.close(); } }

Como podemos ver, el método para actualizar es muy similar al método para guardar la entidad. Lo mismo ocurre con el método para eliminarla, "eliminaContacto": public void eliminaContacto(Contacto contacto) throws HibernateException { try { iniciaOperacion(); sesion.delete(contacto); tx.commit(); } catch (HibernateException he) { manejaExcepcion(he); throw he; }finally { sesion.close(); } }

Ahora veremos unos métodos un poco más interesantes. Cuando queremos buscar una entidad podemos usar varios criterios. La forma más fácil es buscar una entidad particular usando su "id". La clase "org.hibernate.Session" proporciona dos métodos para esto: "load" y "get". Los dos hacen prácticamente lo mismo: en base al identificador y tipo de la entidad recuperan la entidad indicada, con la diferencia de que "load" lanza una excepción en caso de que la entidad indicada no sea encontrada en la base de datos, mientras que "get" simplemente regresa "null". Pueden usar el que prefieran, en lo personal me gusta más "get", así que lo usaré para el método "obtenContacto": public Contacto obtenContacto(long idContacto) throws HibernateException { Contacto contacto = null; try { iniciaOperacion(); contacto = (Contacto) sesion.get(Contacto.class, idContacto);

} finally { sesion.close(); } return contacto; }

Finalmente veremos el método "obtenListaContactos" que recupera todos los Contactos que estén guardados en la base de datos. Como en este caso regresaremos una lista de elementos deberemos crear una consulta. Cuando tenemos que crear una consulta con JDBC lo hacemos en SQL, sin embargo con Hibernate tenemos varias opciones:   

Usar una query en SQL nativo. Crear una query en HQL (Hibernate Query Language). Crear una query usando Criteria que es un API para crear queries de una forma más "orientada a objetos".

Critera es, a mi parecer, la forma más fácil de crear las queries. Sin embargo, también en mi opinión, HQL es más poderosa y tenemos más control sobre lo que está ocurriendo, así que será esta forma la que usaremos. Creando la consulta en HQL Hibernate la transformará al SQL apropiado para la base de datos que estemos usando. La consulta en realidad es muy simple: indicamos que queremos obtener datos (generar un "SELECT"), en este caso la clausula "SELECT" no es necesaria (aunque si existe) porque vamos a regresar todos los datos del objeto (podemos indicar solo unos cuantos atributos, eso es llamado proyección, pero se maneja de una forma distinta). Lo que si debemos indicar es de cuál clase queremos recuperar las instancias, por lo que necesitamos la clausula "FROM" y el nombre de la clase (recuerden que en base al nombre de la clase Hibernate sabrá en cuál tabla están almacenadas las entidades). Espero que esta explicación se haya entendido, se que es un poco enredado, pero quedará más claro con el ejemplo: public List obtenListaContactos() throws HibernateException { List listaContactos = null; try { iniciaOperacion(); listaContactos = sesion.createQuery("from Contacto").list(); }finally { sesion.close(); } return listaContactos; }

Eso es todo, nuestra consulta para recuperar todos los Contactos que tenemos en la base de datos solo debemos usar la clausula "FROM Contacto". Si quieren una referencia más amplia de HQL pueden encontrarla en el tutorial sobre HQL. Bien, eso es todo. La clase "ContactosDAO" queda de la siguiente forma (omitiendo los imports):

public class ContactosDAO { private Session sesion; private Transaction tx; public long guardaContacto(Contacto contacto) throws HibernateException { long id = 0; try { iniciaOperacion(); id = (Long) sesion.save(contacto); tx.commit(); } catch (HibernateException he) { manejaExcepcion(he); throw he; } finally { sesion.close(); } return id; } public void actualizaContacto(Contacto contacto) throws HibernateException { try { iniciaOperacion(); sesion.update(contacto); tx.commit(); } catch (HibernateException he) { manejaExcepcion(he); throw he; } finally { sesion.close(); } } public void eliminaContacto(Contacto contacto) throws HibernateException { try { iniciaOperacion(); sesion.delete(contacto); tx.commit(); } catch (HibernateException he) { manejaExcepcion(he); throw he; } finally {

sesion.close(); } } public Contacto obtenContacto(long idContacto) throws HibernateException { Contacto contacto = null; try { iniciaOperacion(); contacto = (Contacto) sesion.get(Contacto.class, idContacto); } finally { sesion.close(); } return contacto; } public List obtenListaContactos() throws HibernateException { List listaContactos = null; try { iniciaOperacion(); listaContactos = sesion.createQuery("from Contacto").list(); } finally { sesion.close(); } return listaContactos; } private void iniciaOperacion() throws HibernateException { sesion = HibernateUtil.getSessionFactory().openSession(); tx = sesion.beginTransaction(); } private void manejaExcepcion(HibernateException he) throws HibernateException { tx.rollback(); throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he); } }

Ahora, y para terminar el ejemplo, haremos uso de "ContactosDAO" para crear y recuperar algunas instancias de "Contacto". Creo que el código es muy claro así que no lo explicaré ^-^!. La clase "Main" queda de la siguiente forma: public class Main { public static void main(String[] args) { ContactosDAO contactosDAO = new ContactosDAO();

Contacto contactoRecuperado = null; long idAEliminar = 0; //Creamos tes instancias de Contacto Contacto contacto1 = new Contacto("Contacto 1", "[email protected]", "12345678"); Contacto contacto2 = new Contacto("Contacto 2", "[email protected]", "87654321"); Contacto contacto3 = new Contacto("Contacto 3", "[email protected]", "45612378"); //Guardamos las tres instancias, guardamos el id del contacto1 para usarlo posteriormente idAEliminar = contactosDAO.guardaContacto(contacto1); contactosDAO.guardaContacto(contacto2); contactosDAO.guardaContacto(contacto3); //Modificamos el contacto 2 y lo actualizamos contacto2.setNombre("Nuevo Contacto 2"); contactosDAO.actualizaContacto(contacto2); //Recuperamos el contacto1 de la base de datos contactoRecuperado = contactosDAO.obtenContacto(idAEliminar); System.out.println("Recuperamos a " + contactoRecuperado.getNombre()); //Eliminamos al contactoRecuperado (que es el contacto3) contactosDAO.eliminaContacto(contactoRecuperado); //Obtenemos la lista de contactos que quedan en la base de datos y la mostramos List listaContactos = contactosDAO.obtenListaContactos(); System.out.println("Hay " + listaContactos.size() + "contactos en la base de datos"); for(Contacto c : listaContactos) { System.out.println("-> " + c.getNombre()); } } }

En el momento que ejecutemos la aplicación Hibernate creará la tabla correspondiente en la base de datos (llamada "contactos") y que tiene los siguientes campos:

Como podemos ver la tabla y los nombres de las columnas se generan en base al archivo de mapeo. En donde hemos colocado los nombres de las columnas se han usado estos nombres, en donde no lo hemos hecho se han tomado los mismos nombres que el de los atributos que estamos mapeando. Si observamos la salida de la consola podemos ver, que en la parte final, se indica esta creación y además las consultas que Hibernate ha generado (revueltas con los mensajes que sacamos a consola). He marcado con rojo los mensajes que mandamos a consola para que sea fácil distinguirlos.

Segun indica la salida en la base de datos solo debemos tener dos entidades, con los nombres "Nuevo Contacto 2" y "Contacto 3". Revisemos la tabla para ver que esto sea correcto:

Como podemos ver, esto es correcto, en la base de datos existen solo los registros indicados, con lo que podemos estar seguros de que nuestra aplicación funciona!!! ^-^. Entonces, vimos que con Hibernate fue muy simple hacer la manipulación de los datos de una base de datos relacional sin escribir una sola línea de SQL. En aplicaciones de tamaño mediano a grande esto nos ahorrará mucho tiempo (que UNMSMlmente usaríamos en escribir el SQL para query, armar algunas de estas de forma dinámica, pasar los parámetros adecuados, recuperar los mismos de un ResultSet, entre otras cosas) para mejorar algunos otros aspectos de la aplicación, como la interfaz gráfica, la lógica del negocio, o realizar más pruebas. Además nuestro código es más simple y por lo tanto fácil de mantener. Lo único malo es que ahora tenemos que crear mapeos de las entidades con las tablas de la base de datos en un archivo XLM. Es por esto que en el siguiente tutorial veremos cómo realizar este mismo ejemplo pero usando anotaciones en vez del archivo de mapeo

13. Proyecto Web de Agentes jade con las tecnologías JSF y Hibernate Consta de dos proyectos un proyecto WEB y un proyecto de Escritorio en el que se implemtaran los agentes JADE y tendrá un proyecto de tipo librería en donde se colocara todo el modelo generado apartir de la base de datos por Hibernate. Para este ejemplo se usara anotaciones en vez del archivo de mapeo xml, para el modelo generado por Hibernate. Para realizar la comunicación entre un proyecto Jade y otro no Jade se necesita de un agente de tipo GatewayAgent que se encuentra en el paquete jade.wrapper.gateway. Tanto el proyecto WEB como el de JADE importan las librerías de HibernateJPA de netbeans 7.1.2 debido a que los dos van a utilizar la base de datos, el de WEB solo para mostrar el contenido de las tablas (reportes) y el de JADE lo hara para el registro. ProyectoWeb: Este proyecto es el que desea comunicarse con los agentes de la plataforma jade para lograr esto Jade dispone de una Agente de tipo GatewayAgent. Para lograr que este agente sea creado es necesario darle ciertos valores iniciales a la clase que inicia a este agente JadeGateway el cual consta de tres métodos principales:   

Init: En este se colocan los valores de iniciación del agente, JadeGateway.init("nombreClaseAgenteGateway", propiedadesdelagente); Execute: Es el comando que crea el agente y además pasa el objeto al método proccesCommand del agente. Shutdown: Elimina al agente.

ProyectoJade: Contiene a la clase AgenteBD de la cual se instancia al agente BD que se encargara deregistrar los valores obtenidos de la aplicación web, en la clase ProyectoJade donde se encuentra el main se crearan todos los agentes que se crea conveniente derivadas de las clases de tipo agente, para nuestro caso solo habrá un agente BD.

LibreríaModelo: Este proyecto de tipo librería solo contiene el dominio o modelo de la base de datos representado en los archivos POJOs para el ejemplo contiene solo un archivo Model1 que representa a la tabla modelo de la base de datos y posee otro archivo llamado MensajeAgente que e usara para enviar el mensaje entre los agentes.

Codigo completo delos proyectos anteriores: LibreriaModelo: package mensaje; import java.io.Serializable; /** * @author UNMSM */ public class MensajeAgente implements Serializable{ private String NombreAgente; private Object o; public String getNombreAgente() { return NombreAgente; } public void setNombreAgente(String NombreAgente) { this.NombreAgente = NombreAgente; }

public Object getO() { return o; } public void setO(Object o) { this.o = o; } public MensajeAgente(Object o, String nombreAgente) { this.o = o; this.NombreAgente = nombreAgente; } public MensajeAgente() { } } package modelo; import javax.persistence.*; /** * @author UNMSM */ @Entity @Table(name = "modelo") public class Model1 implements java.io.Serializable { @Column(name = "nm", nullable = false, length = 50) private String nm; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "id") private long id; public Model1() { } public Model1(String nm) { this.nm = nm; } public String getNm() { return this.nm; } public void setNm(String nm) { this.nm = nm; } public long getId() { return id; } public void setId(long id) { this.id = id; } }

Clases comunes para el proyecto JADE y WEB package dao; import java.util.logging.Level; import java.util.logging.Logger; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; /** * * @author user */ public class DAO { private static final SessionFactory sessionFactory; private static final ThreadLocal session = new ThreadLocal(); private static final Logger log = Logger.getAnonymousLogger(); static { try { // Create the SessionFactory from standard (hibernate.cfg.xml) // config file. sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static Session getSession() { Session secion = (Session) DAO.session.get(); if (secion == null) { secion = sessionFactory.openSession(); DAO.session.set(secion); } return secion; } protected void begin() { getSession().beginTransaction(); } protected void commit() { getSession().getTransaction().commit(); } protected void rollback() { try { getSession().getTransaction().rollback(); } catch (HibernateException e) { log.log(Level.WARNING, "Cerrando", e); } DAO.session.set(null); }

public static void close() { getSession().close(); DAO.session.set(null); } protected DAO() { } }

package implementacion; import dao.DAO; import java.util.List; import mensaje.MensajeAgente; import modelo.Model1; import org.hibernate.HibernateException; import servicios.Interface; /** * * @author user */ public class ImpInterface extends DAO implements Interface { @Override public List listarDatos() throws Exception { List listaContactos = null; try { begin(); listaContactos = getSession().createQuery("from Model1").list(); commit(); } finally { DAO.close(); } return listaContactos; } @Override public void regDato(Object o) throws Exception { System.out.println("Registrando dato ingresado por el usuario"); MensajeAgente m = (MensajeAgente) o; try { begin(); getSession().save((Model1)m.getO()); commit(); } catch (HibernateException e) { throw new Exception("Error de registro", e); } DAO.close(); } }

package servicios; import java.util.List; /** * @author UNMSM */ public interface Interface { public List listarDatos()throws Exception; public void regDato(Object o) throws Exception; }

ProyectoJade package proyectojade; import jade.core.Profile; import jade.core.ProfileImpl; import jade.wrapper.AgentController; import jade.wrapper.ContainerController; import jade.wrapper.StaleProxyException; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author UNMSM */ public class ProyectoJade { /** * @param args the command line arguments */ private static ContainerController cc; private static AgentController ac; public static void main(String[] args) { jade.core.Runtime rt = jade.core.Runtime.instance(); Profile p = new ProfileImpl(); //

p.setParameter(Profile.FILE_DIR, ProyectoJade.class.getResource("/mtps/").getPath()); p.setParameter(Profile.CONTAINER_NAME, "Administracion");//se le asigna un nombre al contenedor cc = rt.createAgentContainer(p); //se crea un contenedor en la plataforma jade if (cc != null) { try { ac = cc.createNewAgent("BD", "agenteSistema.AgenteBD", null); ac.start(); } catch (StaleProxyException ex) { Logger.getLogger(ProyectoJade.class.getName()).log(Level.SEVERE, null, ex); } } }

}

package agenteSistema; import implementacion.ImpInterface; import jade.core.AID; import jade.core.Agent; import jade.core.behaviours.CyclicBehaviour; import jade.domain.DFService; import jade.lang.acl.ACLMessage; import java.util.logging.Level; import java.util.logging.Logger; import mensaje.MensajeAgente; import modelo.Model1; import servicios.Interface; /** * @author UNMSM */ public class AgenteBD extends Agent { Model1 m = new Model1(); Interface registro; protected void setup() { addBehaviour(new CyclicBehaviour(this) { @Override public void action() { System.out.println("Esperando mensaje"); ACLMessage msg = blockingReceive(); if (msg != null) { System.out.println("Mensaje recibido"); registro = new ImpInterface(); ACLMessage respuesta = new ACLMessage(ACLMessage.INFORM); respuesta.setPerformative(ACLMessage.INFORM); try { if (msg.getContentObject() instanceof MensajeAgente) { MensajeAgente m1 = (MensajeAgente) msg.getContentObject(); registro.regDato(m1); respuesta.addReceiver(new AID(m1.getNombreAgente(), AID.ISGUID)); respuesta.setContentObject((Model1) m1.getO()); send(respuesta); } } catch (Exception ex) { Logger.getLogger(AgenteBD.class.getName()).log(Level.SEVERE, null, ex); } } } }); } protected void takeDown() { try { DFService.deregister(this); } catch (Exception e) { } } }

ProyectoWeb Pagina index.xhtml Facelet Title

Pagina reporte.xhtml Reporte Reporte de registros de la base de datos

package controlador; import gateway.JadeGatewayFactory; import implementacion.ImpInterface; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import modelo.Model1; import servicios.Interface; /** * * @author user */ @ManagedBean @RequestScoped public class ControlEjem {

private modelo.Model1 model1; private List ln;

public List getLn() { return ln; } public void setLn(List ln) { this.ln = ln; } public Model1 getModel1() { return model1; } public void setModel1(Model1 model1) { this.model1 = model1; } public String listar() { Interface in = new ImpInterface(); try { ln = new ArrayList(); ln = in.listarDatos(); } catch (Exception ex) { Logger.getLogger(ControlEjem.class.getName()).log(Level.SEVERE, null, ex); } return "reporte"; } public void registrar() throws Exception { JadeGatewayFactory.execute(model1); System.out.println("Respuesta de AgenteGateway"); }

public ControlEjem() { model1 = new Model1(); } }

package agente; import jade.core.AID; import jade.core.behaviours.CyclicBehaviour; import jade.lang.acl.ACLMessage; import jade.lang.acl.UnreadableException; import jade.wrapper.gateway.GatewayAgent; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import mensaje.MensajeAgente; import modelo.Model1; /** * * @author UNMSM */ public class AgenteGateway extends GatewayAgent { Model1 model1 = null; @Override protected void processCommand(java.lang.Object obj) { System.out.println(getLocalName() + " Realizando el mensage"); try { ACLMessage msg = new ACLMessage(ACLMessage.REQUEST); System.out.println("Creando mensaje"); if (obj instanceof Model1) { MensajeAgente msa = new MensajeAgente(); System.out.println("Entrando al mensaje"); model1 = (Model1) obj; msa.setO(model1); msa.setNombreAgente(getAID().getName()); msg.addReceiver(new AID("BD", AID.ISLOCALNAME)); msg.setContentObject(msa); System.out.println("Agente a enviar mensaje: " + getAID().getName()); send(msg); } } catch (IOException ex) { Logger.getLogger(AgenteGateway.class.getName()).log(Level.SEVERE, null, ex); } } public void setup() { addBehaviour(new CyclicBehaviour(this) { @Override public void action() { System.out.println("Iniciando el comportamiento"); ACLMessage msg = receive(); if (msg != null) {

try { if (msg.getContentObject() instanceof Model1) { System.out.println("Nombre del agente que envia un mensaje: " + msg.getSender().getLocalName()); Model1 m1=(Model1) msg.getContentObject(); model1.setId(m1.getId()); model1.setNm(m1.getNm()); releaseCommand(model1); } } catch (UnreadableException ex) { Logger.getLogger(AgenteGateway.class.getName()).log(Level.SEVERE, null, ex); } } else { block(); } } }); super.setup(); } }

package gateway; import jade.core.Profile; import jade.util.leap.Properties; import jade.wrapper.ControllerException; import jade.wrapper.StaleProxyException; import jade.wrapper.gateway.JadeGateway; /** * * @author UNMSM */ public class JadeGatewayFactory { public static void inicializaGateway() { Properties jadeProps = new Properties(); jadeProps.setProperty(Profile.MAIN_PORT, "1099"); jadeProps.setProperty(Profile.CONTAINER_NAME, "Gateway"); JadeGateway.init("agente.AgenteGateway", jadeProps); } public static void execute(Object command) { inicializaGateway(); try { JadeGateway.execute(command); JadeGateway.shutdown(); } catch (StaleProxyException ex) { ex.printStackTrace(); } catch (ControllerException ex) { ex.printStackTrace(); } catch (InterruptedException ex) { ex.printStackTrace(); } } }

14. Ingenias (IDK) Creando un Agente Hola mundo en Ingenias



Crear diagrama de agentes. Click derecho sobre la carpeta Project -> Add AgentModel Lo llamaremos Hola Mundo

El contenido de este modelo consta de un agente, objetivo(goal), tarea, estado mental, frame fact.



Crear un diagrama de tareas y objetivos. Click derecho sobre la carpeta Project -> Add TaskAndGoalsModel Lo llamaremos SaludarUsuario

El contenido de este modelo consta: tarea saludar, Objetivo Saludar Usuario y FrameFact Contenidodelsaludo. Todos estos creados en el modelo de Agentes.



Crear un diagrama de componentes. Click derecho sobre la carpeta Project -> Add ComponentDiagram Lo llamaremos Componentes.

El contenido de este modelo consta: tarea saludar y de un CodeComponent (se deja con sus valores por defecto para este ejemplo). La tarea saludar viene del modelo de Agentes.

Definimos que va a realizar el componente a través de la tarea. Le damos doble click al codecomponent agregado luego nos dirigimos a la parte de Code y digitamos un mensaje system.out.println(“Hola Mundo”); y luego presionamos aceptar. Como se muestra en la figura.

Generar código: Modules-> Code Generator-> Ingenias Agent Framework generator -> generate La pestaña Log mostrara el resultado.

Ejecutar el código generado. Se debe abrir dos consolas de comando desde la carpeta del proyecto.  La primera ejecutara el RMA de jade de la siguiente manera ant runjade.



la segunda ejecutara al depurador IAF de ingenias y además creara en iniciara a nuestro(s) agente del proyecto. Escribiendo lo siguiente ant run. El mensaje “Hola Mundo” aparece al final.

Crear un diagrama de despliegue

El contenido de este modelo consta: DeploymentPackage al cual nombraremos DespliegueTresAgentes y un DeploymentUnitByType al cual nombraremos AgentesSaludando, a este último le definiremos el tipo de agente que ejecutara y cuántos de estos va a crear mediante el paquete de despliegue (DeploymentPackage). Como se muestra en la figura.

De esta figura en la parte de AgentTypeDeployed -> class.ingenias.editor.entitiesAgent -> Select existing En donde escogemos a nuestro agente hola mundo.

En la parte NumberInstances colocamos el número 3, el cual nos indica que se ejecutaran tres agentes hola mundo. Para ejecutar este despliegue se debe tener levantada la plataforma de jade como se mostro anteriormente y luego en la segunda consola ejecutar ant runDespliegueTresAgentes. Ver la figura.

En la parte final se muestran los tres mensajes “Hola mundo” de cada uno de los agentes y en el administrador de jade “RMA” se ven a los tres agentes creado en un container aparte del MainContainer.

15. Bibliogafia. http://www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html http://jade.tilab.com/doc/index.html http://programacionjade.wikispaces.com/

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF