miércoles, 19 de junio de 2013

HornetQ: Instalación

Embarcado en otro proyecto, me toca realizar funciones de "arquitecto de software", para montar una plataforma de distribución de mensajes.
Con un sistema de distribución de datos (o en inglés Data Distribution System, o DDS) se prentende establecer un control de flujo de información, proveniente de varias fuentes de información y consumida o procesada por varias aplicaciones, con propósitos individuales distintos.
Conocí de la existencia de este tipo de middleware en un anterior proyecto, pero no tuve la ocasión de  poner en marcha un sistema como éste... hasta ahora!

Así pues, lo primero que he hecho es informarme de que sistemas DDS existen y me llamó la atención HornetQ. Dispone de versiones para Windows y Linux, así que para no perder el hilo de aprendizaje y que los conocimientos no cayeran en el olvido, me he decidio a crear una máquina virtual con un Ubuntu Server 12.04 (de esto ya os hablaré otro día, centrémonos en lo que nos concierne ahora) para disponer de un servidor virtual dónde instalar HornetQ.

Y para instalarlo procedo del siguiente modo:

  1. En mi directorio raíz, /home/cesc/ 
    1. wget http://downloads.jboss.org/hornetq/hornetq-2.2.14.Final.tar.gz
  2. Como me gusta tener las cosas bien ordenadas, decomprimo el fichero 
    1. tar -xvzf hornetq-2.2.14.Final.tar.gz 
  3. Y lo muevo a /usr/local/, carpeta dónde se suelen instalar las aplicaciones de usuario.
    1. sudo chmod 775 /usr/local
    2. mkdir /usr/local/hornetq
    3. mv hornetq-2.2.14.Final/* /usr/local/hornetq/
  4. Guardo el fichero .tar.gz y quito las referencias a hornetq de mi directorio
    1. rm hornetq-2.2.14.Final
      rmdir hornetq-2.2.14.Final

Salvando los últimos pasos, lo importante es saber de dónde descargar la versión de HornetQ y el comando para descomprimir los ficheros. Desde la página de descargas de HornetQ podéis comprobar la última versión final del producto.

Entrando un poco en distribución de carpetas, me gusta tener acceso fácil a los contenidos. Y más cuando se trabaja en modo de comando. Así que utilizando la instrucción 
ln -s nombre_directorio nombre_enlace 
Me he creado una serie de enlacen en mi directorio raíz para acceder más rápidamente a los contenidos.

  1. ln -s /usr/local/hornetq/bin ./hornetq
  2. ln -s /usr/local/hornetq/config ./hornetq_config
El resultado final a este proceso


martes, 17 de enero de 2012

Herramienta para Interficies Web

Y para poder "consumir" los servicios web, una herramienta que, en un primer vistazo, parece que va a dar mucho juego: UI Builder para consumir Web Services

Tutorial de Web Services

He aquí un enlace bastante útil: Web Cast de creación de servicios Web

viernes, 25 de enero de 2008

PFC: redactar en XP

No he escrito hasta ahora porque estaba centrado en la programación de la aplicación.
Aunque se tenga que seguir un diseño o un análisis o unas especificaciones, me temo que he estado siguiendo un modelo de implementación extrema o Extreme Programming, XP, para los entendidos en diseño y análisis. Así que, siguiendo este modelo, se piensan las funcionalidades, se implementan y se prueban para que todo funcione correctamente.
Al acabar es cuando uno para a documentar lo que se ha hecho. Ha habido pocos quebraderos de cabeza, siempre antes de la programación de cualquier funcionalidad, pero no se ha detenido lo suficiente para pensar en ello detenidamente; se ha hecho.

Y ya con un 75% del total del proyecto acabado, queda un 5% que corresponde a una ultima funcionalidad de la aplicación y un 20% que corresponde a escribir la documentación.

Ahora queda... quizá una parte difícil del PFC que es la de organizar las ideas, los hechos, la teoría empleada y plasmar lo que se ha aprendido y lo que se ha construido a partir de los conocimientos; plasmar cómo debe ser utilizado; plasmar los resultados obtenidos e identificar por dónde se puede mejorar o ampliar la aplicación.
Hay que tenerlo listo para la presentación final.

martes, 18 de diciembre de 2007

PFC: nombres, "entre comillas"

Uso pgAdminIII para administrar la base de datos de mi proyecto. Y la gestión que hago de los datos almacenados en ella esta programada en código JAVA.

En alguna ocasión tengo que recurrir al uso de alguna función o procedimiento para la gestión de estos datos. Así que usando pgAdminIII y su asistente para la creación de funciones o procedimientos es bastante sencillo crearlas.
¿Cómo accedo a la creación de éstas? Lee con atención: de la jerarquía de objetos que cuelgan de una base de datos, en el marco dónde cuelgan las base de datos que administrar, encuentra los objetos Funciones o Procedimientos (o Functions o Procedures). Al clicar con el botón derecho encima de estas... llamémoslas entradas, seleccionar la opción Nueva Función o Nuevo Procedimiento - la diferencia entre estas dos es que la primera devuelve un valor o conjunto de valores con parámetros de entrada, mientras que la segunda no devuelve nada pero trabaja con parámetros de entrada i salida -.

Al clicar sobre el nombre de la función o procedimiento, en el marco de abajo se puede ver la instrucción SQL que las crea. Observa que el nombre se halla entre comillas dobles; e aquí el problema. Porque desde JAVA no hay manera de crear un String con comillas dobles en su interior, ya que un String se delimita por comillas dobles (lector, si hay una manera de hacerlo, ¡dímelo!). Entonces ¿no se puede llamar a un procedimiento/función desde JAVA? Si se puede. Ese código SQL se puede editar, basta con copiarlo en el editor SQL (el icono de una hoja con un lápiz) de pgAdminIII y ejecutarlo desde el mismo editor - se puede crear una Función o Procedimiento sin necesidad de asistente -. En el editor le quitamos las comillas dobles al nombre y tenemos creada la función con un nombre accesible desde JAVA.

PFC: hint o tooltip

Quiero que, para cada componente contenido en los formularios de la aplicación de mi proyecto, se muestre el típico mensaje de ayuda, que aparece cuando se pasa el ratón por encima.
Bueno, he tenido que encontrar en la red, y más concretamente en este artículo que no existe una propiedad Hint en para los componentes de los formularios en las nuevas versiones de .NET.
Lo que si que existe es un componente llamado ToolTip que se añade a cada formulario. Este componente no es más que el componente que codifica el mensaje que queremos que aparezca cómo ayuda. Lo que en versiones viejas de Visual Studio, el Visual Basic antepasado de .NET, se hacia directamente con darle valor a la propiedad Hint de los componentes, ahora se hace con el componente ToolTip.

Y ¿cómo añado yo ese comentario de ayuda? Nada más sencillo que añadir un componente ToolTip al formulario y, automáticamente, aparece para cada componente una propiedad llamada ToolTip in tooltip1 (o cómo llamemos al componente).
En esta propiedad se escribe el mensaje que queremos mostrar, mientras que en las propiedades del componente ToolTip se cambian valores cómo AutomaticDelay, BackColor, IsBalloon, ... (ya sabes que dejo para ti, estimado lector/aprendiz, divagar por ti solo, y si tienes dudas, no tienes que hacer más que preguntar.)

martes, 27 de noviembre de 2007

PFC: proceso con estados

El ciclo de vida de un agente se pude entender como una sucesión de estados. El comportamiento de un agente se puede programar con varios comportamientos o con un comportamiento compuesto continente de otros.
FSMBehaviour es uno de estos comportamientos compuestos. De manera secuencial, y definiendo transiciones entre estados, se implementa la acción que debe realizar el comportamiento. Pero FSMBehaviour carece de método action(), con lo que la implementación de estados y transiciones debe realizarse en el constructor o en su método onStart() o justo después de añadir el comportamiento en el nacimiento del agente.

public class MaquinaEstados extends FSMBehaviour
{
private static final String STATE_1 = "1";
private static final String STATE_2 = "2";
private static final String STATE_3 = "3";

public MaquinaEstados(Agent _agente)
{
super(_agente);
}

public void onStart()
{
registerFirstState(new OneShotBehaviour1(agente));
registerState(new OneShotBehaviour2(agente));
registerLastState(new OneShotBehaviour3(agente));

Los estados de un agente, con FSMBehaviour, son los distintos comportamientos que forman parte de este comportamiento compuesto.
Se definen unas constantes cómo etiquetas para identificar los estados. Hay que registrar los distintos comportamientos que componen FSMBehaviour a modo de estados, registrando cada cual cómo primer estado, último estado y estado intermedio.

registerDefaultTransition(STATE_1, STATE_2);
registerTransition(STATE_2, STATE_1, 0);
registerTransition(STATE_2, STATE_3, 1);
}
}

Para controlar el flujo de ejecución, basta con definir varias transiciones entre los estados registrados. Las transiciones puede ser por defecto - el flujo de ejecución siempre va del estado/comportamiento origen al estado/comportamiento destino - o teniendo en cuenta un valor de salida del comportamiento origen, que será devuelto por el método onEnd() de cada comportamiento. Este valor va a depender de las condiciones de ejecución que se implementen en cada estado/comportamiento.

public class OneShotBehaviour2 extends OneShotBehaviour
{
private int exitValue;
...
public void action()
{
if (true)
exitValue= 1;
else
exitValue= 0;
}
...
public int onEnd()
{
return exitValue;
}
}

sábado, 17 de noviembre de 2007

PFC: nacer y morir

En la POA con JADE, existe un agente llamado DF (Directory Facilitator) . Dicho agente se encarga de guardar la descripción y dirección de los agentes que viven en un mismo sistema. Proporciona un servicio de páginas amarillas al cual los demás agentes acceden para saber la dirección de otros y poder comunicarse entre ellos.

Cuando se crea un agente, la primera tarea que debe hacerse en su nacimiento, en su método setup(), es la de registrarse en el DF.

public class Jane extends Agent
{
...
public void setup()
{
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(this.getAID()); //una descripción con su identificador
ServiceDescription sd = new ServiceDescription();
sd.setType("agente_recomendador");
sd.setName(this.getName());
dfd.addServices(sd);
DFService.register(this, dfd);
...
}

Para registrarlo, utilizamos el método estático register(Agent, DFAgentDescription) del DF, pasándole por parámetros el tipo de agente que es (instancia de la clase que implementa) y su descripción. Y aquí ya tenemos listo al agente para ser localizado dentro del sistema.
Al terminar la aplicación, todos los agentes mueren al mismo tiempo que se cierra la JVM dónde residen todos los agentes. Pero ¿si queremos dar por terminado un agente sin tener que cerrar la JVM?
Cuando un agente termina su actividad, pasa de estado ACTIVE a DELETED, ejecuta su método interno takeDown(). En este método tenemos que quitar el agente del DF para que ningún otro se pueda comunicar con él.

...
public void takeDown()
{
...
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(this.getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType("agente_recomendador");
sd.setName(this.getName());
dfd.addServices(sd);
DFService.deregister(this, dfd);
}
}

Basta con llamar al método estático deregister(Agent, DFAgentDescription) para acabar con él. La API de este método permite varias maneras de quitar del DF a un agente. Fijaros que he incluido la misma descripción para registrarlo que para quitarlo del registro. Así me aseguro que sólo ese agente va a ser eliminado.
Pero, ¿porqué no llamar a DFService.deregister(), sin parámetros? Con esta última solución eliminaría a todos los agentes que implementan la misma clase, cosa que para mi proyecto no me interesa, porque en el sistema tengo varios agentes de la misma clase y se puede dar el caso que un agente recomendador tenga que hacer cálculos mientras que otro ya ha acabado.

sábado, 10 de noviembre de 2007

PFC: entender un mensaje

Cómo un agente puede tener varios comportamientos, cada uno de ellos va a actuar según el tipo de mensajes que reciba.
Habéis leído ( o decido de la lectura) que un mensaje se lo identifica por un tipo o performativa. Con el envío y recepción de mensajes de performativas relacionadas se puede identificar una conversación entre agentes, con la cual se maneja el flujo de datos y la ejecución de algoritmos entre ellos. Por ejemplo,

CFP (Call For Proposal)
ACCEPT-PROPOSAL
REJECT-PROPOSAL
PROPOSE

son performativas que pueden ayudarnos a crear una comunicación de negociación entre agentes. Pero, ¿cómo se sabe que mensaje ha de recibir un comportamiento? Basta con declarar una variable de tipo jade.lang.acl.MessageTemplate e indicarle que patrón debe tener el mensaje que tiene que recibir. Siguiendo el ejemplo visto en el mini artículo anterior:

template= MessageTemplate.and(
MessageTemplate
.MatchConversationId("consulta_bd"),
MessageTemplate.MatchInReplyTo(mensaje.getReplyWith()));

indico al agente que el mensaje que tiene que identificar y tratar debe contener un conversationId = "consulta_bd" y que debe ser una respuesta o réplica del mensaje que le he enviado. Mirad la documentación de jade.lang.acl.MessageTemplate para más detalles.

PFC: comunicacion interagente

Uno de los puntos fuertes de la POA es la programación de mensajes. Con éstos, se establece comunicación entre agentes que estan en ejecución. A modo de conversación entre ellos, en una POA tiene que haber mensajes que se envian o se reciben por uno u otro agente, a modo de ejecución de órdenes y devolver respuestas.

Un primer agente crea un mensaje :
ACLMessage mensaje = new ACLMessage(ACLMessage.REQUEST);
mensaje.addReceiver(agente); //destinatario del mensaje
mensaje.setConversationId("consulta_bd"); //un identificador de la conversación
mensaje.setReplyWith("consulta_bd"+System.currentTimeMillis());
mensaje.setContent("te envio un mensaje"); //contenido del mensaje
myAgent.send(mensaje);

El mensaje es de tipo jade.lang.acl.ACLMessage. El destinatario de éste se define mediante la variable jade.core.AID agente, y con setContent(String msg) se indica el qué va a contener el mensaje. Los otros métodos sirven para identificar el mensaje, para quién hay que responderlo, etc.

Y para contestar a este mensaje, otro agente crea una réplica del mensaje recibido por el primer agente:
ACLMessage recibido = myAgent.receive(template); //recibe un tipo de mensaje
ACLMessage replica= recibido.createReply();
replica.setPerformative(ACLMessage.INFORM); //tipo de mensaje
replica.setContent("te envio una respuesta");
myAgent.send(replica);

Un punto a destacar de la comunicación es cómo definir el tipo de mensaje empleado. Existen varios actos comunicativos que permiten distinguir una comunicación de otra, pudiendo ser procesados, en paralelo, por varios comportamientos de un agente.

miércoles, 31 de octubre de 2007

sumar valor a una fecha

Una de las muchas complicaciones de la programación en JAVA es la programación de fechas. En mi proyecto necesito incrementar el valor de una fecha para trabajar con periodos de tiempo.
El uso de fechas no es trivial, requiere mirar mucha documentación y aprender de ejemplos para no cometer fallos. Y mirando por la red, esta vez si, he encontrado una solución.

Basta con crear un objeto jade.util.Calendar y añadirle valores posteriormente, para luego añadirle un incremento, más o menos siguiendo estas lineas:

String [] dataTemp;
DateFormat df= new SimpleDateFormat("dd/MM/yyyy");

dataTemp= _data.split("/");
Calendar c= Calendar.getInstance();
c.set(Integer.parseInt(dataTemp[2]), Integer.parseInt(dataTemp[1])- 1, Integer.parseInt(dataTemp[0]));
c.add(Calendar.DATE, incremento);

siendo incremento el valor que quiero sumar, en este caso, al día de la fecha (se indica o Calendar.MONTH o Calendar.YEAR si se incrementa el valor del mes o del año, respectivamente).
Con el método set(int, int, int), introduzco al Calendar los valores de año, mes y día, por este orden (fijaros que al valor del mes lo decremento en uno, porque Calendar trata los meses desde 0 a 11).
He podido comprobar, también, que al sumar un incremento que pueda dar un valor superior al valor máximo de un mes, el valor del mes también se incrementa, por sí solo, dando lugar a una fecha correcta.

jueves, 25 de octubre de 2007

... y manejar componentes a la vez

El uso de Thread, del que hablo en el anterior mini artículo, lo aplico a controlar algoritmos que se ejecutan en los formularios de la aplicación cliente. Y al crear un hilo distinto, y toquetear componentes del formulario lleva a un conflicto.
Existe un primer hilo de ejecución (¡supongo que anda por ahí!, o al menos eso dice el compilador) que retiene el funcionamiento de los componentes y no deja que otros hilos modifiquen el estado de éstos. P.ej. desde un segundo hilo quiero escribir cosas a un listBox que tiene el formulario, la ejecución falla.
Y para subsanar está pequeña herida hay que utilizar el código siguiente:

//en los atributos del formulario
delegate void metodoCallback(parámetros);
...
public void recomendation()
{
metodo(parámetros)
}
public void metodo(parámetros)
{
if (this.listBox1.InvokeRequired)
{
metodoCallback process = new metodoCallback(metodo);
this.Invoke(process, new object[] { parámetros });
}
else
{
this.listBox1.Add(parámetros) //por ejemplo
}
}

Aquí, yo quiero llenar una lista, así que la lleno en la condición else del método. Todo lo demás es para hacer que este método manipule el contenido del listBox.
Cómo no he investigado más a fondo para entenderlo; sólo he buscado resultados, no puedo ofreceros una explicación más detallada. No es parte fundamental de mi proyecto así que esto ya sirve.

miércoles, 24 de octubre de 2007

varias tareas... (usando Threads)

Parte de la programación del proyecto se centra en seguir un diseño cliente/servidor. La parte cliente, implementada en c#, es la encargada de enviar peticiones y recibir resultados. Las peticiones son mensajes para obtener datos de una base de datos.
El proceso que debe ejecutar el cliente es largo: incluye varios envíos y recibimientos, por lo que no quiero que se quede bloqueado a la espera de que acabe dicho proceso (no es un requerimiento indispensable para el proyecto, pero ¡me picaba el gusanillo!)

He estado probando implementaciones, consultando de aquí para allá para utilizar Thread en c#, y quiero dejar parte de lo que he estado aprendiendo.
Cuando se inicia el proceso, el código del botón que lo pone en marcha ejecuta lo siguiente:

using System.Threading;
...
Thread hilo =
new Thread(new ThreadStart(recomendation));
hilo.name = "hilo";
if (!hilo.IsAlive)
{
hilo.Start();
}

Al constructor del Thread se le pasa un parámetro, que es el nombre del método que ejecutará, siendo:

private void recomendacion()
{
//lógica del algoritmo
...
hilo.Abort();
}

un método que ni lleva parámetros ni devuelve ningún valor. El código de este método será el que ejecute el hilo recientemente creado.
Y así puedo toquetear otras tareas de la aplicación, mientras el proceso está en marcha. Fijaros que añado el método Abort(). Lo llamo nada más acabar el proceso que ejecuta el método, para terminar el Thread. Este método lanza una excepción System.Threading.ThreadAbortException que no cojo porque no es necesario.

martes, 23 de octubre de 2007

PFC: seguimiento de la comunicación

El agente software se comporta a modo de hilo de ejecución o Thread. Sabiendo esto, uno se puede imaginar que seguir el camino por dónde pasa el código es un poco difícil, debido a su carácter concurrente, que no se sabe si ha pasado por aquí, si está interrumpido... y más si aportas al Thread una autonomía a base de estados, que si active, wait, suspended, running, blocked - los tres primeros estados pertenece a la clase Agent y los dos últimos a la clase Behaviour -.

Habéis leído que para ejecutar código java con agentes hay que escribir en el intérprete de comandos lo siguiente:

java jade.Boot -gui "nombre_agente_1":"clase_java_agente_1"(parámetros)

Fijaros que utilizo la opción -gui. Ésta lanza el agente RMA (Agente de Monitorización Remota o Remote Monitoring Agent para los cultos) que permite ver que agentes están activos dentro de la JVM. (RMA es un agente con una pantalla gráfica asociada). Desde el RMA se pueden lanzar otro agentes que ayudan a controlar la existéncia de los nuestros.
Uno de mucha utilidad (y que utilizo bastante) es el agente Sniffer. Dicho agente permite monitorizar la comunicación que existe entre los nuestros y el contenido de dicha comunicación. Se puede ver el paso de mensajes de unos a otros aún estando creados y en ejecución, porque el agente mostrará cómo ha sido la comunicación entre ellos; en que dirección se han enviado los mensajes.

viernes, 19 de octubre de 2007

PFC: ... digo main

Ya os hablé que en POA no hay un método main, ni nos hace falta una clase main porque JADE tiene su manera de arrancar una aplicación. Pero ha surgido una cuestión que era necesaria utilizar en mi proyecto fin de carrera. Me he visto en la obligación de implementar unas líneas de código para crear agentes en tiempo de ejecución; es decir, que debo crear agentes por código y no sólo tener varios agentes creados inicialmente, al lanzar la aplicación.

El trozo de código que me permite crear agentes dinámicamente es:

Object[] arguments = new Object[]{"a", "b"};
PlatformController plataforma = this.getContainerController();
AgentController control =
plataforma.createNewAgent("nombre_agente"+ _numero, "paquete.claseAgente", arguments);
control.start();

Cómo parámetros hay que pasar un nombre para el agente (yo añado el parámetro _numero para distinguir a los diferentes agentes que voy a crear), la clase que implementa el código del agente y los argumentos del agente.

Los agentes viven en un contenedor ubicado en la JVM. Con este código se obtiene dicho contenedor, que está creado debido a que al lanzar la aplicación, lanzo también varios agentes que sí quiero que estén siempre activos, mientras el código servidor esté funcionando (esto ya prepara a la JVM para acoger a agentes). Tiene que existir otra solución para poder crear dicho contenedor en la JVM y poder crear agentes desde código. Sospecho que las clases PlatformController y AgentController tiene algo que ver.