actas del ii congreso javahispano

116
Copyright y permisos de reproducción: los trabajos contenidos en estas actas se hallan bajo la licencia de javaHispano (http://www.javahispano.org/licencias/index.html). En lo relativo javaHispano se permite la reproducción total o parcial de los trabajos siempre que se referencie debidamente el lugar original de publicación del trabajo y a sus autores. Los respectivos autores de cada trabajo pueden imponer restricciones adicionales para su reproducción, por lo que para reproducir total o parcialmente alguno de los trabajos de esta acta javaHispano recomienda contactar directamente con sus respectivos autores. Editado por Abraham Otero Quintana. ISBN 84-689-0035-4 Actas del II congreso javaHispano

Upload: others

Post on 17-Jul-2022

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Actas del II congreso javaHispano

Copyright y permisos de reproducción: los trabajos contenidos en estas actas se hallan bajo la licencia de javaHispano (http://www.javahispano.org/licencias/index.html). En lo relativo javaHispano se permite la reproducción total o parcial de los trabajos siempre que se referencie debidamente el lugar original de publicación del trabajo y a sus autores. Los respectivos autores de cada trabajo pueden imponer restricciones adicionales para su reproducción, por lo que para reproducir total o parcialmente alguno de los trabajos de esta acta javaHispano recomienda contactar directamente con sus respectivos autores.

Editado por Abraham Otero Quintana.

ISBN 84-689-0035-4

Actas del II congreso javaHispano

Page 2: Actas del II congreso javaHispano

Actas del II congreso javaHispano

Page 3: Actas del II congreso javaHispano

Índice

Prefacio…………………………………………………………………..………………………………....… 5

Comité de Organización……………..………………………..………..…………….…………......… 6

Comité de revisión…………….…………………..…………….....………………………………...… ..7

Presentaciones invitadas………………….……………………..………………………………...… ..8

Annotation Driven AOP (AOP orientado a anotaciones)..…………………………………………..….......9

Alexandre Vasseur

Modern Java Bottom-up Software Composition Techniques: Revisiting Jini, AOP-Style

(Técnicas de composición de software modernas, del detalle al concepto: repaso a Jini,

con estilo AOP) …………………….………………………………………………………………………..... 10

Hugo Pinto

Taming the Tiger (Domesticando al Tigre)…………………….…………………………………………… 11

Neal Gafter y Joshua Bloch

Still More Programming Puzzlers (Más soluciones para los rompecabezas de programación)..……. 12

Neal Gafter y Joshua Bloch

¿Has dicho Middleware?...................................................................................................................13

Miguel Valdes-Faura

Articulos…………………..…………………………………………………………………………….…… 17

SIMToolkit: la última frontera para la integración total, en la palma de tu mano……….................. 19

Alejandro Seco Calero y David Fraga Aydillo

Aplicaciones de tratamiento de imagen en terminales J2ME con cámara…….…………………..…... 27

Jonatan Tierno Alvite y Celeste Campo Vázquez

Programación de dispositivos Bluetooth a través de Java……………………………….…..…….…….. 35

Alberto Gimeno

Memoria dinámica en JavaCard: una herramienta para superar las limitaciones…………..…….…... 41

Borja Bravo Alférez y David Fraga Aydillo

JVMTI, Creación avanzada de profilers de aplicaciones con la nueva API de Tiger …………..…...…. 49

Daniel Glez-Peña y Florentino Fdez-Riverola

Actas del II congreso javaHispano

Page 4: Actas del II congreso javaHispano

JNIEasy: Aspect Oriented Programming a la ayuda de Java como ciudadano de

primera clase en el desktop ……………………………………………………………………………. 57

Jose Maria Arranz

Guasaj: Un framework de programación basado en componentes ………………..……….…..... 65

Urko Benito Mateo, Ángel Blesa Jarque y José Javier Lop lis Extensión del patrón Observador para la integración de eventos de componentes

heterogéneos ……………………………………………………………………………………...….…. 73

Luis Rodero, Miguel A. Ortuño y Luis López

Seguridad no intrusiva con Acegi Security System for Spring …………………….…..……...…... 79

Carlos Sánchez

Estándares libres y Java: ¿Es el JCP un organismo que crea estándares libres?………...……..... 87

A. Otero

Integración continua utilizando herramientas Open Source……………………..…………..….... 99

Jesús Perez

Caso de uso: Empleo de tecnologías J2EE para el desarrollo de una plataforma

para la gestión tecnológica………………………………………………………….....………..….... 107

Rafael Pedraza, Alberto Planas, Antonio Navarro, Benjamín de la Fuente y Jose David Fernández

Actas del II congreso javaHispano

Page 5: Actas del II congreso javaHispano

Prefacio

Organizar el congreso hispano independiente sobre Java más grande del mundo no es una tarea fácil. Cuando alguien llega al mostrador de un congreso como este no solo recoge una acreditación de plástico, sino los frutos del trabajo de mucha gente. Un trabajo constante de varios meses al que multitud de personas se han dedicado con un único objetivo: extender el uso de Java en todo el mundo hispano. Con este mantra en la cabeza desde la organización del congreso, hemos coordinado el esfuerzo de ponentes de varios países de habla hispana. Especial mención y agradecimiento merecen en este apartado las ponencias que hemos recibido de países como Colombia, México y Ecuador entre otros, y que debido a limitaciones presupuestarias y organizativas nos hemos visto tristemente empujados a desestimar en esta edición. Por supuesto los agradecimientos no se pueden quedar ahí. Esta magnifica reunión hubiera sido imposible sin la gente que habla - nuestros grandes ponentes -, sin la gente que nos apoya - nuestros patrocinadores - y por supuesto sin los que escuchan, asistentes que han empleado sus vacaciones, sus recursos o simplemente su tiempo libre para que todo el esfuerzo del resto de personas no fuera en vano. Y el resultado de las interacciones de todas estas personas es el que tiene ahora en sus manos. Unas actas que recogen al detalle las diferentes charlas que, siempre siguiendo un riguroso nivel de calidad, exponen diferentes temas de máxima actualidad en el presente. Áreas como AOP, arquitectura, software libre, movilidad y JDK 5.0, todo ello expuesto por ponentes punteros en sus respectivos campos que se han prestado a compartir con todos nosotros sus conocimientos y experiencias. Y es precisamente ese espíritu de comunidad y el deseo de promover un intercambio de ideas es el que se haya al fin y al cabo detrás de la propia asociación javaHispano. Siempre hemos pensado que la tecnología es una herramienta para construir futuro, que en los países de habla hispana esta requiere de una mayor atención debido al retraso acumulado con respecto a los países anglosajones y que nosotros podíamos hacer algo para cambiar esta situación y convertir al castellano en una lengua que no sea remolcada, sino tractora dentro del campo de la tecnología en general y de Java particular. Esperamos haberlo conseguido. Al menos hasta la siguiente edición.

Aitor García Rey Pedro del Gallego Vida

Presidente del comité de organización Presidente del comité de programa

Actas del II congreso javaHispano

5

Page 6: Actas del II congreso javaHispano

Comité de organización

• Presidente: Aitor García Rey. javaHispano, España.

• Alberto Molpeceres Touris, javaHispano, España.

• Álvaro Sánchez-Mariscal Arnaiz, javaHispano, España.

• Martín Pérez Mariñán, javaHispano, España.

• Abraham Otero Quintana, javaHispano, España.

• Isaac Ruiz Guerra, javaHispano, México.

• Enrique Rodríguez Lasterra, javaHispano, España.

• Pedro del Gallego Vida, javaHispano, España.

• Ignacio Brito Calahorro, javaHispano, España.

• Eduardo Millán Martínez, javaHispano, España.

• Emilio Escobar Reyero, javaHispano, España.

• Jesús Navarrete Izquierdo, javaHispano, España.

• Jose Luis Mondelo, javaHispano, España.

• Roberto Andradas Izquierdo, Capítulo de Estudiantes de ACM de la Universidad Rey Juan Carlos

• Álvaro Navarro Clemente , Capítulo de Estudiantes de ACM de la Universidad Rey Juan Carlos

Actas del II congreso javaHispano

6

Page 7: Actas del II congreso javaHispano

Comité de revisión

• Presidente: Pedro del Gallego Vida, javaHispano, España.

• Aitor García Rey. Responsable de Proyectos, Grupo AIGE.

• Alberto Molpeceres Touris, Arquitecto Jefe de Software, NHT-Norwick.

• Álvaro Sánchez-Mariscal Arnaiz, Analista, IT Deusto.

• Emilio Escobar Reyero, Analista, ISOTROL SA.

• Ignacio Brito Calahorro, Ingeniero de Software Senior, QualityObjects.

• Isaac Ruiz Guerra, javaHispano, México.

• Jesús Navarrete Izquierdo, javaHispano, España.

• Martín Pérez Mariñán, Arquitecto de Software, DINSA Soluciones.

Actas del II congreso javaHispano

7

Page 8: Actas del II congreso javaHispano

Actas del II congreso javaHispano

8

Page 9: Actas del II congreso javaHispano

__________________________________________________________________________________

__________________________________________________________________________________

Actas del II congreso javaHispano

9

Page 10: Actas del II congreso javaHispano

Actas del II congreso javaHispano

10

Page 11: Actas del II congreso javaHispano

Annotation Driven AOP

(AOP orientado a anotaciones)

Alexandre Vasseur

Abstract

Esta ponencia proporciona una introducción a los conceptos de la Programación Orientada a Aspectos (AOP) e intenta explicar cómo las Anotaciones en Java 5 (JSR- 175) y AOP pueden ser utilizados conjuntamente. La ponencia ofrece varios ejemplos de código basados en AspectWerkz, un marco de trabajo de código abierto Java/XML AOP puro. La primera parte trata de proporcionar un conocimiento básico acerca de los conceptos AOP en general, y cómo dichos conceptos se concretan en código Java, en los que se mejoran las clases regulares con Anotaciones Java 5 y se transforman en aspectos. Se detallan conceptos de Anotaciones predefinidas, proporcionadas por el marco de trabajo para definir nuevas construcciones – exactamente en el caso de los web services (JSR-181). Las Anotaciones también pueden ser definidas por el usuario y utilizadas en aplicaciones para implementar un comportamiento específico, basado en acceso en tiempo de ejecución a las Anotaciones. El marco de trabajo AOP AspectWerkz soporta coincidencias en esas Anotaciones de propósito específico, de forma que provee de un robusto mecanísmo de coincidencias basado en tipos. AOP y las Anotaciones no son contendientes sino que se complementan mútuamente y, cuando se utilizan conjuntamente, pueden ser una herramienta muy potente; nosotros creemos que esto va a jugar un papel importante en los futuros desarrollos y estándares Java. Esta ponencia proporciona una introducción a los conceptos de la Programación Orientada a Aspectos (AOP) e intenta explicar cómo las Anotaciones en Java 5 (JSR- La charla concluye con una explicación de cómo estos conceptos se pueden utilizar hoy en día, y cómo las mismas funcionalidades pueden ser utilizadas gracias a las Anotaciones basadas en Java 1.3/1.4 doclet.

Actas del II congreso javaHispano

11

Page 12: Actas del II congreso javaHispano

Modern Java Bottom-up Software Composition Techniques: Revisiting Jini, AOP-Style

(Técnicas de composición de software modernas, del detalle al concepto: repaso a Jini, con estilo AOP)

Hugo Pinto

Abstract

En esta charla, Hugo Pinto analiza las tendencias actuales en técnicas de Separación de Conceptos (Separation of Concerns, SoC) basadas en Java(TM), mayormente enfocadas a la descomposición multidimensional (tal como se hace en AOSD), y argumenta que tales aproximaciones, si se aplican a los componentes de sistema además del propio código, amplía enormemente las posibilidades de distribuir y hacer disponible software Java orientado a SOA, muy en la línea de cómo fue propuesto por la Tecnología de Red Jini(TM) en sus orígenes. Hugo establece un paralelismo entre una aproximación Java basada en AOP y Jini 2, y construye el caso en el que se puede crear software con características Jini basándose en componentes de servicio AOP cuidadosamente diseñados, que de esta forma permiten una máxima flexibilidad e interoperabilidad en el diseño de software Java.

Actas del II congreso javaHispano

12

Page 13: Actas del II congreso javaHispano

Taming the Tigre (Domesticando al Tigre)

Neal Gafter y Joshua Bloch

Abstract

La reciente aparición de la nueva versión de la plataforma Java (J2SE 5.0, también llamada Tiger) incluye nuevas y excitantes características: generics, enums, autoboxing, for-each, varargs, static import y annotations (metadatos). Unidas, todas estas características incrementan en gran medida la facilidad de programación, mientras que disminuyen la probabilidad de error. Esta charla presenta una introducción a todas las nuevas características, y cuenta cuándo y cuándo no se debe utilizar cada una de ellas. Se proporciona gran cantidad de ejemplos de código.

Actas del II congreso javaHispano

13

Page 14: Actas del II congreso javaHispano

Still More Programming Puzzlers

(Más soluciones para los rompecabezas de programación)

Neal Gafter y Joshua Bloch

Abstract

Joshua Bloch y Neal Gafter (también conocidos como "clic and Hack, the Type-It brothers") presentan ocho rompecabezas más para nuestro entretenimiento y aclaración. El formato de la demostración del juego nos mantiene atraídos mientras que los rompecabezas nos enseñan las delicadezas del lenguaje de programación de Java y de sus librerías fundamentales. Cualquier persona con un conocimiento práctico del lenguaje será capaz de entender los rompecabezas, pero incluso desafiarán a los veteranos más experimentados. Las lecciones ofrecidas en esta ponencia serán directamente aplicables a vuestros programas y diseños. Y algunas de las bromas pueden incluso ser divertidas.

Actas del II congreso javaHispano

14

Page 15: Actas del II congreso javaHispano

¿Has dicho Middleware?

Miguel Valdes-Faura

Abstract

Actas del II congreso javaHispano

15

Page 16: Actas del II congreso javaHispano

Actas del II congreso javaHispano

16

Page 17: Actas del II congreso javaHispano

__________________________________________________________________________________

__________________________________________________________________________________

Actas del II congreso javaHispano

17

Page 18: Actas del II congreso javaHispano

Actas del II congreso javaHispano

18

Page 19: Actas del II congreso javaHispano

SIMToolkit: la última frontera para la integración total, en la palma SIMToolkit: la última frontera para la integración total, en la palma SIMToolkit: la última frontera para la integración total, en la palma SIMToolkit: la última frontera para la integración total, en la palma

de tu mano.de tu mano.de tu mano.de tu mano.

Alejandro Seco CaleroAlejandro Seco CaleroAlejandro Seco CaleroAlejandro Seco Calero [email protected]

David Fraga AydilloDavid Fraga AydilloDavid Fraga AydilloDavid Fraga Aydillo [email protected]

AbstractAbstractAbstractAbstract

EEEEl avance de la tecnología móvil parece no tener freno a día l avance de la tecnología móvil parece no tener freno a día l avance de la tecnología móvil parece no tener freno a día l avance de la tecnología móvil parece no tener freno a día

de hoy. de hoy. de hoy. de hoy. Los terminaLos terminaLos terminaLos terminales móvilesles móvilesles móvilesles móviles se renuevan cada menos se renuevan cada menos se renuevan cada menos se renuevan cada menos

tiempotiempotiempotiempo y las posibilidades que ofrecen se multiplican de y las posibilidades que ofrecen se multiplican de y las posibilidades que ofrecen se multiplican de y las posibilidades que ofrecen se multiplican de

igual manera. En este documento realizaremos un análisis igual manera. En este documento realizaremos un análisis igual manera. En este documento realizaremos un análisis igual manera. En este documento realizaremos un análisis

de las posibilidades ofrecidas por tecnologde las posibilidades ofrecidas por tecnologde las posibilidades ofrecidas por tecnologde las posibilidades ofrecidas por tecnologías incluídas enías incluídas enías incluídas enías incluídas en

nuestro móvil como sonnuestro móvil como sonnuestro móvil como sonnuestro móvil como son Java Card (SIMToolkit) Java Card (SIMToolkit) Java Card (SIMToolkit) Java Card (SIMToolkit) y y y y J2ME. La J2ME. La J2ME. La J2ME. La

tecnologítecnologítecnologítecnología SIMToolkit nos ofrece laa SIMToolkit nos ofrece laa SIMToolkit nos ofrece laa SIMToolkit nos ofrece la posibilidad de crear en posibilidad de crear en posibilidad de crear en posibilidad de crear en

lalalala t t t tarjeta SIM una aplicación diseñada por nosotrosarjeta SIM una aplicación diseñada por nosotrosarjeta SIM una aplicación diseñada por nosotrosarjeta SIM una aplicación diseñada por nosotros, y , y , y , y

realizar desde ella operaciones desde nuestro menúrealizar desde ella operaciones desde nuestro menúrealizar desde ella operaciones desde nuestro menúrealizar desde ella operaciones desde nuestro menú. P. P. P. Por or or or

otro lado el desarrollo de aplicaciones para J2ME (midlets) otro lado el desarrollo de aplicaciones para J2ME (midlets) otro lado el desarrollo de aplicaciones para J2ME (midlets) otro lado el desarrollo de aplicaciones para J2ME (midlets)

nos presenta tonos presenta tonos presenta tonos presenta todo el potencial del API de MIDP tanto a do el potencial del API de MIDP tanto a do el potencial del API de MIDP tanto a do el potencial del API de MIDP tanto a

nivel gráfico como de comunicaciones. nivel gráfico como de comunicaciones. nivel gráfico como de comunicaciones. nivel gráfico como de comunicaciones. Estudiaremos Estudiaremos Estudiaremos Estudiaremos

oportunidades que nos ofrecen ambas plataformas de cara oportunidades que nos ofrecen ambas plataformas de cara oportunidades que nos ofrecen ambas plataformas de cara oportunidades que nos ofrecen ambas plataformas de cara

a la comunicacia la comunicacia la comunicacia la comunicación con el exteriorón con el exteriorón con el exteriorón con el exterior, y de igual forma , y de igual forma , y de igual forma , y de igual forma

analizaremos la viabilidad de unir ambos mundos.analizaremos la viabilidad de unir ambos mundos.analizaremos la viabilidad de unir ambos mundos.analizaremos la viabilidad de unir ambos mundos. Las Las Las Las

posposposposibilidades que se nos ofrecen son muy amplias, y en ibilidades que se nos ofrecen son muy amplias, y en ibilidades que se nos ofrecen son muy amplias, y en ibilidades que se nos ofrecen son muy amplias, y en

base a ellas propondremos líneas futuras y de aplicación.base a ellas propondremos líneas futuras y de aplicación.base a ellas propondremos líneas futuras y de aplicación.base a ellas propondremos líneas futuras y de aplicación.

Keywords: Keywords: Keywords: Keywords: J2ME, Midlet, MIDP, GPRS, CSD, JavaCard,

Smart Card, SMS, evento, proactivo, SIMToolkit(STK).

1 Introducción al entorno de aplicac1 Introducción al entorno de aplicac1 Introducción al entorno de aplicac1 Introducción al entorno de aplicaciónióniónión

Hoy en día nos movemos cada vez más en un

entorno móvil donde los dispositivos de reducido

tamaño, inalámbricos, y de altas prestaciones son

cada vez más comunes en nuestros bolsillos. Dentro

de dicho mundo, no cabe duda, que el gran

protagonista en la actualidad es el teléfono móvil.

La ventaja sustancial que nos ofrece la movilidad

frente a otros dispositivos no quedaría reflejada si

no desarrolláramos convenientemente la capacidad

de comunicación entre nuestros terminales. El

intercambio de información entre dispositivos

móviles es imprescindible a la vez que lógico. Desde

nuestro móvil de bolsillo podemos, a día de hoy,

desde mandar un mensaje de texto, navegar por un

buscador de Internet o establecer una

videoconferencia con nuestro colega americano,

hasta descargarnos nuestra melodía favorita y todo

ello lo asumiremos como servicios en su mayor

parte habituales. Así pues el término

comunicaciones junto a movilidad van unidos de

forma irrevocable.

El planteamiento desde el punto de vista de usuario

de cara a su terminal parece sencillo. Los requisitos

fundamentales son interfaces gráficas vistosas, y

funcionalidades cada vez más avanzadas, pero la

base de todos estos elementos se desarrolla en un

motor de procesado cada vez más potente. Cada vez

más, el terminal móvil adquiere funcionalidades

similares a un ordenador convencional, y entre ellas

hay que destacar las librerías de comunicaciones.

Nuestro sistema va a estar dotado de un amplio

abanico de posibilidades a la hora de conectarse al

exterior. Deberemos tener siempre presente las

posibles redes de comunicaciones que nos vamos a

encontrar: red GSM, red GPRS (sobre GSM), red

UMTS, Internet, redes privadas y redes de área

personal (IrDa, Bluetooth, … ). Hoy en día una de las

redes de mayor uso es la red GPRS dimensionada

sobre su predecesora GSM.

Figura 1: Estructura de red GPRS

Actas del II congreso javaHispano

19

Page 20: Actas del II congreso javaHispano

Otro factor clave en el mundo de las tecnologías

móviles es la tendencia hacia la universalización y

estandarización de dispositivos. Los terminales van

a ser desarrollados bajo plataformas muy similares,

de forma que el desarrollo de aplicaciones para cada

uno de ellos sea idéntico y no sea necesario

realizarlo y adaptarlo para cada uno.

Entre las tecnologías que mejor resumen todos los

aspectos que se han reseñado encontramos aquellas

que se sitúan tanto a nivel de terminal: Java2 ME

(plataforma miembro de la familia de productos Java

adaptado a terminales o dispositivos de reducido

tamaño) y Symbian (sistema operativo desarrollado

por un consorcio de compañías del sector, el cual

permite la programación de aplicaciones por parte

del usuario), como tecnologías en el ámbito de

nuestra tarjeta SIM: Java Card [2] (plataforma de Java

adaptada para tarjetas inteligentes o smart cards,

que cuenta con su propia maquina virtual) y, a un

nivel superior a Java Card, encontramos la interfaz

SIMToolkit [1], que adapta las posibilidades de una

tarjeta SIM al mundo Java. Adentrándonos en el

mundo de la tarjeta SIM lo que nos ofrece el entorno

de desarrollo SIMToolkit [1] es la unión de los

mundos de tarjetas inteligentes y nuestro terminal.

Mediante una API propia vamos a ser capaces de

desarrollar aplicaciones que puedan correr en

nuestra tarjeta, y que posean una interfaz de cara al

usuario en el display del móvil, siendo los aspectos

visuales opcionales.

Veamos a continuación la estructura de la familia de

productos Java 2 , donde aparecen desmarcados en

la parte derecha los productos destinados a

dispositivos móviles y smart cards.

Figura 2 : Plataforma Java 2

La tarjeta SIM va a ser considerada como un

periférico adicional dentro de los elementos que

componen un terminal móvil. La tarjeta adquirirá un

carácter pasivo. Este rol pasivo se define así ya que

para que la tarjeta pueda enviar información hacia el

exterior (terminal) recurrimos a un petición de

estado continua desde el terminal y en nuestra

respuesta desde la tarjeta le indicaremos nuestro

estado junto con la invocación de alguna función a

realizar (comandos proactivos).

Entenderemos nuestro terminal móvil como un

microprocesador (como hemos comentado,

actualmente cada vez son más potentes) con el cual

interactuamos mediante distintos periféricos, tales

como el teclado, el display, audífono o,

concretamente, nuestra tarjeta SIM. Por ello cada

uno de estos elementos adquiere gran importancia

para la composición final del dispositivo, pero

especialmente la tarjeta SIM será la que nos permita

comunicarnos hacia el exterior. Desde la tarjeta

vamos a poder controlar el acceso a la red. La

operadora nos va a permitir acceder a sus servicios a

través de la clave encriptada que reside en nuestra

tarjeta. Así pues tendremos acceso a los

mecanismos de comunicaciones de nuestra red:

SMS, llamadas de voz, llamadas de datos,

señalizaciones, etc. No solo se va a poder acceder a

estos servicios si no además la tarjeta va a disponer

de acceso a información sensible como agenda o

mensajes, almacenados en la propia SIM

Desde el punto de vista del terminal vamos a

concebir el dispositivo como un pequeño ordenador

desde el que podremos ejecutar aplicaciones

gráficas, descargar contenidos o conectar con un

servidor de correo, todo ello por la capacidad de

procesado de la que dispone.

La estandarización de tarjetas SIM parece obvia

mientras que por el contrario, a nivel de terminales

encontramos en el mercado mucha mayor

diversificación. Cada terminal de un fabricante

distinto llevará muy posiblemente un procesador

diferente pero nos basamos en un de los pilares

fundamentales de J2ME, su portabilidad entre

distintas máquinas. Todo el desarrollo realizado

para nuestra investigación se ha realizado siempre

en diversos tipos de móviles encontrando variedad

de recursos implementados por los mismo, pero

manteniendo el núcleo del API de J2ME siempre que

Actas del II congreso javaHispano

20

Page 21: Actas del II congreso javaHispano

este estuviera soportado (con su correspondiente

perfil MIDP)

Así pues, con todo lo aquí planteado, parece verse

que delante de nosotros tenemos dos mundos a

simple vista diferentes, en primer lugar el lado

terminal, y por otro el lado tarjeta SIM. Los dos nos

ofrecen numerosas posibilidades, y por ello, nuestro

primer objetivo será el control de ambos campos,

desde la programación básica general hasta el

control de librería de comunicaciones. Una vez

alcanzado este objetivo nuestra línea de desarrollo

tenderá hacia la unión de ambos entornos, con el fin

de poder procesar información desde un lado y

recibirla en el otro, obtener conectividad desde la

tarjeta SIM hacia nuestro terminal móvil y viceversa.

2 SIMToolkit2 SIMToolkit2 SIMToolkit2 SIMToolkit (STK) (STK) (STK) (STK)

La comunicación entre nuestra tarjeta y el terminal

móvil se lleva acabo gracias a una API concreta, STK.

Esta API está estructurada dentro de las normas de

Java Card, por lo que el desarrollo de una applet

seguirá el mismo procedimiento que el de una

aplicación en el entorno de tarjetas inteligentes.

Puntualizaremos que para el desarrollo de una

aplicación para Smart Cards deberemos implementar

una serie de funciones guión pues el entorno de

ejecución estará predeterminado para buscar estas

funciones. Entre estos métodos encontramos:

install(), destroy(), o process(). Métodos que no

vamos a entrar a desarrollar por entender que

forman parte del entorno de tarjetas inteligentes y

salen del contexto de nuestro artículo. Destacar que

una diferencia de STK respecto a Java Card simple es

que la primera implementa la función

processToolkit() , similar a process() en Java Card y

será ésta la que se ejecute en el momento de

activación de nuestra aplicación.

El formato de transferencia de información desde

una Smart Card (SIM en nuestro caso) recibe el

nombre de APDU. Por consiguiente el terminal móvil

también va a esperar recibir este tipo de paquetes

desde nuestra tarjeta. La estructura de un ADPU es

muy sencilla. Poseen dos campos iniciales, uno de

clase de instrucción (CLA) y otro de de operación a

ejecutar (INS), seguidos de dos campos P1 y P2 que

serán parámetros opcionales, Le (tamaño en bytes

de la respuesta esperada, Lc (tamaño en bytes del

campo de datos) adjunto y el campo de datos en

cuestión. Tras el envío de un APDU se esperan

respuestas con un formato concreto y sencillo (Ej,

0x9000 Ok). Será sobre este perfil dónde interactúe

STK definiendo un protocolo entre ambos lados. En

el cuerpo de los datos enviados en el APDU

mandaremos información con cabeceras definidas

por STK, y de la misma forma en los códigos de

respuesta podrá venir información adicional con

formato STK. La comunicación en éste ámbito se va

a ver diferenciada por el origen y destino que tenga,

así, diferenciaremos entre mensajes de SIM a

terminal y vicerversa, dando lugar respectivamente,

a los que llamaremos comandos proactivos y

eventos.

Comandos Proactivos

Un comando proactivo es aquel lanzado por la

tarjeta SIM y cuyo destino es el propio terminal,

pidiéndole a éste que realice alguna operación

concreta. Existen 31 comandos proactivos posibles

para poder enviar a nuestro terminal. Los

dividiremos en 4 categorias:

• Applications commands, para desarrollar

aplicaciones típicas de STK.

• Smart-card commands, destinado a

interoperar con otras tarjetas SIM

introducidas en nuestro terminal.

• General communications commands,

interfaz para los distintos tipos de

portadoras soportadas.

• System Commands, orientados a la

sincronización con el terminal y la red.

Una vez nos adentramos dentro del bloque de datos

del APDU, observamos que los comandos proactivos

están divididos en una nueva estructura. Los

bloques que vamos a encontrar dentro del Data load

del APDU son denominados TLV (Tag-Length-

Values). Cada TLV va a venir definido por un campo

Tag, a modo de identificador, un campo de bytes

indicando el tamaño del siguiente campo, y el

campo value, donde encontraremos el verdadero

valor a nivel de datos. Podremos encontrar varios

TLV’s concatenados. A modo de ejemplo: podemos

encontrarnos un Data load en un APDU(SIM->MOVIL)

donde un primer TLV nos indique el tipo de

proactivo que se envía (Tag = comando proactivo,

length = 1, value = Display text), un segundo TLV

Actas del II congreso javaHispano

21

Page 22: Actas del II congreso javaHispano

Móvil SIM

Tag Length Value

Data CLA INS P1 P2 Lc

TLV

APDU

Tag Length Value

INS P1 P2 Lc

TLV

APDU

CLA Data

STK

Smart Card

indicaría una seria de comandos que no entramos a

valorar y un tercer TLV nos indicaría qué texto

queremos sacar por el display.

Figura 3 : Estructura del APDU

Eventos

Mas allá de poder dar la tarjeta SIM órdenes a

nuestro terminal a través de comandos proactivos, la

propia tarjeta podrá registrar una serie de eventos

que serán lanzados desde el terminal. Entendemos

este proceso como el paso de información desde el

terminal hacia la tarjeta lo cual siempre parece más

lógico y por ello su mayor facilidad para

implementar. Recordamos que la tarjeta adquiere un

modo pasivo a la hora de poder enviar proactivos

hacia el terminal. Realizando una caracterización de

los eventos disponibles según su categoría,

encontramos los siguientes grupos principales:

- Notificaciones de mensajes.

- Notificaciones de llamadas, y datos.

- Notificaciones de actividad o selecciones de

menú por parte del usuario.

- Cambios de estado a nivel de celda

Entraremos a continuación a valorar posibles

desarrollos y funcionalidades aplicando

directamente los conceptos aquí descritos.

GESTIÓN DE LA INFORMACIÓN DE LA TARJETA

Como hemos mencionado anteriormente contamos

en nuestro desarrollo con el API ofrecido por STK.

Este API nos ofrecerá el entorno necesario para

manejar comandos proactivos y eventos. De la

misma forma nos ampliará posibilidades al

ofrecernos una interfaz Java que nos permitirá

acceder a la información contenido en la tarjeta SIM:

-La tarjeta como elemento de almacenaje que es,

estará compuesta por un sistema de ficheros con

unas características especiales, debido a su limitada

capacidad, pudiendo acceder a este sistema de

ficheros desde el API de STK (apertura, lectura,

escritura)

–Seremos capaces de poder acceder a los mensajes

cortos almacenados en nuestra tarjeta y de igual

manera a almacenamientos de mensajes entrantes

en la misma. (recordamos que tendremos manejo

total sobre mensajes entrantes, evento SMS-PP)

-Podremos editar y obtener información de las

entradas en nuestra agenda personal SIM.

-La tarjeta telefónica convencional guarda en

memoria las últimas llamadas de voz realizadas, y

de la misma forma podremos acceder a ellas para

comprobar sus destinatarios y duraciones.

GESTIÓN DE LOS PROCESOS DE COMUNICACIÓN CON

EL TERMINAL

El planteamiento que acabamos de realizar para el

desarrollo de aplicaciones desde STK (información

de la tarjeta) no lleva acabo transferencia de

información a través de eventos y proactivos. Todo

se realiza desde la misma tarjeta la cual obtiene

información propia, aunque si necesitamos de

proactivos para el envío de esta información hasta el

display (proactivo DISPLAY TEXT).

Las posibilidades que nos ofrece STK son mucho

más amplias, y gran parte de ellas tienen que ver

con las funciones de comunicación de nuestro móvil.

Los tres canales fundamentales de flujo de

información (llamadas de voz, SMS y conexiones de

datos) podrán ser controlados desde nuestra

aplicación STK.

EL API STK nos ofrece la posibilidad de controlar

tanto los mensajes cortos salientes como los

entrantes, pudiendo actuar dependiendo de su

naturaleza de forma distinta. Existirán dos eventos

distintos para cada una de las direcciones de envío

del mensaje (saliente-entrante). Puntualizaremos,

que al igual que todos los procesos anteriormente

descritos, estas funcionalidades quedan fuera de la

vista del usuario, al cual podremos informarle de las

funciones llevadas acabo a través del display

únicamente (proactivo que deberemos ejecutar).

Actas del II congreso javaHispano

22

Page 23: Actas del II congreso javaHispano

Si nuestros mensajes pueden estar bajo control, no

iban a ser menos las llamadas. Tendremos la

posibilidad de realizar llamadas a un número

concreto, y de tomar acciones a nuestra elección si

una determinada llamada llega a nuestro móvil.

Por último destacar la posibilidad de controlar flujos

de datos desde nuestro terminal. Los canales

permitidos serán bien CSD o GPRS, determinando en

una configuración de parámetros sus respectivas

calidades de servicios. Seremos capaces por tanto de

abrir el canal de datos, obtener información y

enviarla para posteriormente cerrar nosotros

mismos el propio canal. Reseñamos numerosas

dificultades que hemos encontrado en este aspecto

en los desarrollos realizamos en el laboratorio por

motivos de configuración de operador, soporte de

transmisión de datos por parte del móvil, y

configuración adecuada de las calidades de servicio

en el propio canal.

OTRAS FUNCIONALIDADES

Que nuestra tarjeta SIM soporte JavaCard y

SIMToolkit no implica que el terminal móvil en el que

esté insertada soporte todos los comandos

proactivos y eventos que están contemplados. Con

ello queremos indicar que, cada terminal,

dependiendo de sus prestaciones nos va a ofrecer la

posibilidad de interactuar con la tarjeta hasta cierto

punto. Se implementarán por parte de fabricante un

cierto grupo de proactivos y eventos a los que

responder. Se ha realizado una pequeña aplicación

capaz de mostrarnos por pantalla aquellos servicios

que el móvil es capaz de procesar.

Una vez planteado que nuestro móvil no tiene

porqué implementar todas las funciones, veremos

algunas de las más interesantes de cara al

programador STK, aparte de las ya vistas:

-Presentación en pantalla de texto, menús, listas y

formularios.

-Respuestas a eventos del usuario: acción sobre

teclas.

-Obtención de parámetro de localización (a nivel de

celdas).

-Obtención de nivel de potencia de las bases más

cercanas.

DESARROLLOS/APLICACIONES

Veremos ahora algunas de las aplicaciones

realizadas basándonos en toda la estructura aquí

resumida:

MECapabilitiesMECapabilitiesMECapabilitiesMECapabilities: El desarrollo de esta aplicación nos

permite obtener una visión completa de las

funcionalidades implementadas en nuestro terminal,

tanto a nivel de proactivos como de eventos. Nos

muestra por pantalla el listado completo o

personalizado de los proactivos/eventos que

deseemos consultar y en base a una consulta en el

propio móvil nos confirma si está soportado.

Los mecanismos para el desarrollo de esta pequeña

aplicación son muy simples. Basándonos en el

evento de acción por parte del usuario (cuando entra

en nuestro menú de aplicación) interactuamos con él

presentándole gráficamente el menú selección desde

el que puede chequear cualquier opción. Desde el

API de STK accedemos a la clase ME Profile y desde

allí podremos chequear cualquier tipo de

evento/proactivo que deseemos.

GestSIMGestSIMGestSIMGestSIM: Completa aplicación basada en la

administración, almacenaje y transferencia de

mensajes y en el control de entradas en la agenda de

la propia tarjeta. Funcionalidades que podemos

aportar con esta aplicación son, por ejemplo, la

actualización de contactos de nuestra agenda al

llegar a una región distinta donde nuestra empresa

posee un grupo de comerciales distintos a la zona

de donde provenimos. Se accede también al control

de llamadas realizadas y salientes, siendo accesibles

para estas los contactos almacenados en nuestra

tarjeta. A través del manejo de información de

mensajes se pueden obtener funciones de

localización derivadas de nuestra posición en el

momento de envío.

Toda la aplicación se basa en la gestión de los

procesos de comunicación del terminal

anteriormente explicados, junto con la interfaz

gráfico común a todas las aplicaciones de cara al

usuario.

ConGPRSConGPRSConGPRSConGPRS: Aplicación aún en proceso de depuración,

que nos permite establecer una conexión de datos a

un servidor remoto, enviando información contenida

en nuestro móvil y cerrando posteriormente todas

las comunicaciones.

Actas del II congreso javaHispano

23

Page 24: Actas del II congreso javaHispano

Para este desarrollo utilizamos los proactivos

destinados a canales de datos (clase ‘e’) , y de igual

forma presentamos los datos por nuestro display.

3 Integraci3 Integraci3 Integraci3 Integración ón ón ón

J2ME bajo sus perfiles y configuraciones nos permite

el desarrollo de aplicaciones dentro del propio

terminal. Estas aplicaciones pueden barajar desde

interfaces gráficos hasta soporte de comunicaciones

vía sockets TCP, es por ello que hemos trabajado en

este sentido para poder explotar especialmente los

recursos de comunicaciones del móvil. Hemos

realizado implementaciones de aplicaciones cliente-

servidor vía sockets TCP, vía protocolo http y envío-

recepción de datagramas. Hasta la versión MIDP2.0

estas son, junto con https, las implementaciones

posibles de elementos de comunicaciones.

Las plataformas desarrolladas en este artículo (J2ME

y STK) nos ofrecen altas posibilidades de desarrollo

respectivamente, estando cada una de ellas en

mundos distintos a pesar de convivir dentro del

propio terminal (móvil y tarjeta). Nos planteamos la

unión de ambos mundos con las ventajas que ello

conllevaría. Realizaríamos la ampliación de cada una

de las API’s por separado, pudiendo interactuar

desde nuestro móvil con la tarjeta SIM y viceversa.

Entre los mecanismos para realizar esta integración

podemos encontrar por ejemplo la implementación

de protocolos propios que utilizando eventos de

captura de llamadas o de mensajes, y de esta forma

interactuar con nuestra tarjeta. Este planteamiento

sería sólo en una dirección de comunicación.

Dejamos al lector discernir sobre posibles formas de

comunicación desde nuestra tarjeta al terminal.

4 Conclusiones4 Conclusiones4 Conclusiones4 Conclusiones

Dos mundos tan aparentemente separados, pero tan

cerca el uno del otro. Siguiendo la línea de la

integración total o parcial de ambas tecnologías

observamos las posibilidades que ofrecerían ambas

juntas. La implementación, especialmente en STK, a

priori puede parecer algo mas difusa que el

desarrollo en J2ME pues en esta última la aportación

por la comunidad Java en esta es mucho mayor, pero

gracias a las normas GSM [5][6], y a la transparencia

y practicidad de lo que se pretende hacer, resulta

muy agradecido el desarrollo de aplicaciones para

tarjetas inteligentes, y entendemos, desde nuestro

punto de vista, que queda mucho camino por

recorrer para STK, teniendo ya una buena base para

empezar a andar.

Por último hacer mención al entorno de desarrollo

de todo nuestro sistema aquí descrito, y es que por

muy bien que diseñemos una applet para nuestra

tarjeta SIM, deberemos transferirla e instalarla en la

tarjeta. SIMAlliance es la organización que ha

estandarizado sus herramientas, de uso público y

con las que recientemente estamos trabajando. Son

de fácil acceso, pero al estar poco extendida entre

desarrolladores esta tecnología, las dificultades que

aún se encuentran para el desarrollo no son pocas.

5 Líneas futuras5 Líneas futuras5 Líneas futuras5 Líneas futuras

No cabe duda que hoy en día la telefonía móvil ha

adquirido un ritmo de crecimiento tecnológico muy

alto. Es por ello por lo que movernos de un concepto

tecnológico a otro nos lleva muy poco tiempo y, a

día de hoy, la telefonía de tercera generación (3G)

está demasiado cerca nuestra como para obviarla.

La adaptación de STK a este nuevo entorno es

necesaria pues todas nuestras tarjetas en breve

estarán insertadas en teléfonos capaces de

conectarse a la red UMTS.

Orientándonos hacia la integración de STK junto a

J2ME, dos plataformas que ya empiezan a convivir

en nuestro dispositivos, encontramos vías de

estudio muy interesantes como el JSR de J2ME,

SATSA. Security and Trust Services API for J2ME es la

especifiación de un paquete de java que puede tener

mucho que decir en el futuro de estas tecnologías.

Con un final Release por parte del JCP de Sun, y a

tan sólo la espera de su implementación por parte

de un fabricante en algún dispositivo, SATSA ofrece

vías de comunicación a nivel APDU desde nuestro

terminal hasta nuestra tarjeta SIM. Seremos capaces

de, realizando la programación de nuestro módulo

Java, realizar ediciones en los mensajes o agenda de

la tarjeta, enviar eventos determinados o realizar un

propio protocolo de comunicaciones entre ambos

dispositivos con el fin de acceder a información en

un momento determinado. Dejaremos en manos del

lector analizar y evaluar otras posibles aplicaciones

bajo esta línea de desarrollo.

Actas del II congreso javaHispano

24

Page 25: Actas del II congreso javaHispano

AgradecimientosAgradecimientosAgradecimientosAgradecimientos

Me gustaría agradecer desde aquí a toda la gente del

Laboratorio de Sistemas Integrados, perteneciente al

Departamento de Ingeniería Electrónica de la

Universidad Politécnica de Madrid la ayuda prestada

para el desarrollo de todas las investigaciones

relacionadas con esta ponencia. Gracias por hacerme

salir cada día sonriendo del laboratorio.

Especialmente a David, la figura que mejor

representa a un tutor cercano, y siempre dispuesto a

ayudar, gracias. Va por vosotros.

ReferenciasReferenciasReferenciasReferencias

[1] Scott B. Guthery, Mary J. Cronin. Mobile Application

Development with SMS and the SIM Toolkit. McGraw-

Hill.

[2] Zhiqun Chen. Java Card Technology for Smart Cards.

Addison Wesley.

[3] Roger Riggs, Antero Taivalsaari, Mark VandenBrink.

Programming with the Java 2 Platform, Micro Edition.

Addison Wesley.

[4] Luis Javier Herrera Maldonado. Tutorial de MIDP ,

Conexión a redes.

http://flanagan.ugr.es/J2ME/MIDP/conexion.htm

[5] ETSI TS 101 267 – GSM 11.14 “Specification of the SIM

Application Toolkit for the Subscriber Identity Module”

[6] ETS 300 608 – GSM 11.11 “Specification of the

subscriber Identity Module”

Actas del II congreso javaHispano

25

Page 26: Actas del II congreso javaHispano

Actas del II congreso javaHispano

26

Page 27: Actas del II congreso javaHispano

Aplicaciones de tratamiento de imagen en terminales J2ME con cámara

Jonatan Tierno Alvite [email protected]

Celeste Campo Vázquez [email protected]

Abstract

En este documento vamos a estudiar la posibilidad de

realizar aplicaciones de tratamiento de imagen sobre

teléfonos móviles con cámara incorporada en J2ME. Esto

implica implementar algoritmos que típicamente tienen alta

carga computacional sobre dispositivos limitados en

memoria y capacidad de proceso, y además sobre J2ME,

que suele ser considerado un lenguaje de programación

poco eficiente, y de posibilidades limitadas dada su

reducida API. Hemos realizado dos aplicaciones de ejemplo:

Un Lector de Colores y un Detector de Movimiento. Después

hemos realizado un estudio sobre las capacidades de un

terminal concreto, tanto en capacidad de proceso como en

la calidad de imagen que podemos obtener. Con estos

datos sacamos conclusiones sobre qué tipo de aplicaciones

es posible realizar en estas condiciones y para qué otras es

necesario buscar una plataforma más potente.

Keywords: Tratamiento de imagen, teléfonos móviles con cámara, MMAPI, ayuda a invidentes.

1 Introducción

Hoy en día muchos teléfonos móviles (y algunas PDAs)

pueden obtener información no sólo de las redes de

comunicaciones a las que están conectados, si no

también del entorno físico, mediante grabación de audio

y video.

Hasta ahora, y centrándonos en la cámara de fotos y

vídeo, esta nueva capacidad se ha utilizado de la misma

forma que en una cámara convencional: se guarda la

fotografía o el archivo de vídeo en el terminal para

recuperarla más tarde o para enviarla a otro dispositivo.

En este documento vamos a discutir la posibilidad de

realizar un cierto procesado sobre esa información antes

de pasar los resultados al usuario.

En este trabajo hemos utilizado terminales de la Serie 60

de Nokia, principalmente el Nokia 6600, y también el

Nokia 3650. Como lenguaje de programación, hemos

utilizado Java 2 Micro Edition (J2ME).

Uno de los posibles usos de estas aplicaciones es la

ayuda a invidentes, pues estamos hablando de

manipular información visual sobre un dispositivo que la

gente usa en su vida cotidiana. Por ello, hemos

implementado dos aplicaciones dirigidas a este fin: La

primera es un Lector de Colores, que permitirá conocer a

un usuario ciego los colores de un objeto al que dirija la

cámara, por ejemplo, una prenda de ropa. La segunda es

un Detector de Movimiento, con el que podrá saber

cuando alguien entra en una habitación, cuando se

apaga o enciende la luz, etcétera.

El resto del documento se organiza de la siguiente

forma: En la sección 2 vamos a hablar de la Mobile

Media API (MMAPI), que es la librería de J2ME que da

acceso a la cámara desde un MIDlet, y del acceso a la

información de las imágenes de la cámara. Tras esto, se

describe la implementación de dos aplicaciones de

ejemplo: el Lector de Colores, al que dedicaremos la

sección 3 y el Detector de Movimiento, que se tratará en

la sección 4. En una segunda parte del proyecto,

realizamos un estudio de un terminal concreto (el Nokia

6600), para determinar su capacidad de ejecutar

aplicaciones de tratamiento de imagen. En la sección 5

hablaremos sobre el acceso a la calidad de las imágenes

disponibles, y en la sección 6, sobre la capacidad de

proceso y la memoria del terminal. Por último, en la

sección 7 usaremos todos los datos obtenidos para

discutir sobre qué aplicaciones pueden implementarse

sobre estos terminales y cuáles no.

2 Mobile Media API (MMAPI) y el acceso a la cámara

La Mobile Media API (MMAPI) es una librería opcional de

J2ME que permite acceder a cualquier tipo de contenido

Actas del II congreso javaHispano

27

Page 28: Actas del II congreso javaHispano

multimedia (imágenes, audio, video), tanto local como

remotamente. También es el interfaz J2ME hacia

grabación de audio y video. El hecho de que sea una

librería opcional significa que pueden ofrecerla tanto

terminales MIDP 1.0 como 2.0. Sin embargo, aquellos

terminales que no dispongan de ella, no tendrán ningún

tipo de acceso Java hacia la cámara.

La MMAPI consigue tratar diversos tipos de contenidos

de la misma manera mediante un alto nivel de

abstracción que esconde las operaciones a bajo nivel que

realiza el sistema operativo. La MMAPI ofrece un interfaz

común a la lectura de datos desde cualquier fuente y en

cualquier formato mediante un Identificador Uniforme

de recursos (URI), que definirá el dispositivo y los

parámetros de reproducción. El acceso a la cámara se

realiza con el URI especial de captura “capture://video”.

Con la llamada “System.getProperty(String key);”

podemos saber si nuestro dispositivo permite captura de

video o no, y en qué formatos.

El programador manejará una realización del interfaz

Player, que creará con un Manager, con la orden “Player

player = Manager.createPlayer(String uriString);”. Con

esto, podemos acceder a las imágenes de la cámara

como un flujo de video . Para tomar una fotografía,

usamos el método VideoControl.getSnapshot(String

imageType), que nos devuelve un fotograma de ese flujo

en el tamaño y el formato que especifiquemos en el

parámetro imageType.

Para que nuestra aplicación pueda obtener información

de esta imagen y realizar un procesado sobre ella,

necesitamos acceder a los pixels. MIDP 2.0 ofrece

directamente esta funcionalidad con el método getRGB()

de la clase Image. Esta es la solución utilizada con el

teléfono Nokia 6600 en las aplicaciones que hemos

implementado en este trabajo.

El teléfono Nokia 3650 es MIDP 1.0 y no disponía de este

método. Una posible solución era el método

“DirectGraphics.getPixels”, de la librería NokiaUI. Sin

embargo esta es un API propietaria y no se encuentra en

todos los terminales Java.

La solución adoptada para el Nokia 3650 fue parsear el

fichero PNG. En este caso fue bastante sencillo, puesto

que la información no estaba comprimida, y sólo

tuvimos que eliminar las cabeceras del fichero. En otros

terminales (por ejemplo, en el Nokia 6600) puede no

darse el caso, siendo entonces esta tarea muy

complicada o incluso inabordable por razones de

eficiencia.

3 Lector de Colores

El lector de colores permite a un usuario conocer los

colores del objeto que esté enfocando con la cámara del

móvil. De esta forma un invidente puede separar la ropa

blanca de la de color para hacer la colada, por ejemplo.

La aplicación está dividida en los siguientes bloques:

captura y muestreo de los pixels, clustering, decisión y

por último, comunicación de resultados.

Al inicializar la aplicación, la cámara se pone en

funcionamiento, y cuando el usuario apunta a un objeto

y pulsa el botón de acción, realizamos la captura y

muestreo de la imagen. En este bloque tomamos una

fotografía mediante el método getSnapshot, y

accedemos a los pixels según hemos descrito más arriba.

De toda la imagen, tomamos una muestra adecuada

para el procesado posterior: 50 píxeles de la parte

central de la imagen. La cifra escogida es un compromiso

entre la información de la imagen presente en la muestra

y el tiempo que tardaremos en realizar el procesado.

Sobre estos pixels vamos a ejecutar el algoritmo de

custering llamado K-medias. El clustering o

agrupamiento consiste en dividir un conjunto

heterogéneo de elementos en grupos o clusters, de

modo que los elementos más parecidos estén juntos.

Cada cluster está representado por un centroide, que

viene a ser el promedio del cluster, por la varianza del

centroide, es decir, la dispersión de los elementos en un

cluster, y su número de elementos. El K-medias, es un

algoritmo simple y rápido que trabaja con un número

fijo de clusters, que en nuestra aplicación serán tres. Esto

significa que podremos averiguar hasta tres colores de

una imagen simultáneamente.

Para implementar el algoritmo necesitamos definir la

distancia entre dos colores. Para esto, en primer lugar

convertimos los valores RGB de los píxeles a coordenadas

HSB (Crominancia, Brillo, saturación), que son más

adecuadas para comparar colores. La distancia entre dos

colores que hemos usado responde a la expresión:

d[(h1,s1,b1),(h2, s2,b2)]= α( h 1-h 2)+β( s 1-s 2)+γ( b1-b2)

donde α, β y γ son coeficientes hallados empíricamente

que representan la importancia de cada una de las tres

características a la hora de diferenciar dos colores.

Actas del II congreso javaHispano

28

Page 29: Actas del II congreso javaHispano

El K-medias es un algoritmo iterativo que precisa una

condición de parada. En nuestro caso, el algoritmo se

detendrá cuando se cumpla cualquiera de dos

condiciones: La primera es que se alcance un número

máximo de operaciones, para evitar que el algoritmo se

ejecute indefinidamente. La segunda es que la suma de

las varianzas de los clusters deje de disminuir, lo que

significaría que más iteraciones no mejoran la

distribución de los elementos en los clusters.

En el bloque de decisión vamos a determinar cuales son

los colores que contienen los clusters hallados. En primer

lugar, debemos averiguar si dos clusters contienen el

mismo color. Para esto, medimos la distancia entre sus

centroides en relación con la varianza de ambos, y

comparamos con un umbral hallado empíricamente.

También debemos decidir si cada cluster contiene pixels

de un solo color o de varios. Para esto, compararemos

la varianza de los clusters con otro umbral. Con estas

comprobaciones, podemos saber cuántos colores

conforman la imagen, y si son más de tres, que es el

número de clusters, emitiremos un mensaje de error.

Después de esto, asignamos a cada centroide una

categoría de color. Para ello, hemos dividido el espacio

HSB en regiones, cada una con un color asociado. Hecho

esto, basta con ver en qué región cae el centroide de

cada cluster.

Por último, tenemos que comunicar los resultados al

usuario. Cada región tiene asociado un fichero de audio

en que una voz pronuncia el nombre del color. Tras la

etapa de decisión, los colores resultantes son emitidos.

Los más abundantes van primero, de forma que el

usuario sepa el color dominante en la imagen.

4 Detector de Movimiento

Esta aplicación muestrea continuamente el flujo de vídeo

ofrecido por la MMAPI en busca de movimiento y,

cuando éste se produce, la aplicación emite un sonido y

muestra la imagen en que éste se produjo. Esta MIDlet

simplemente compara una imagen con la anterior en un

bucle, y de éste si son distintas, sale del mismo.

La comparación entre dos imágenes es muy simple para

permitir que el bucle sea tan rápido como sea posible, y

que la velocidad esté limitada por la máxima frecuencia a

la que la que podemos llamar al método getSnapshot().

Por esta misma razón, esta velocidad de muestreo puede

no ser constante.

Para detectar el movimiento, simplemente comparamos

el color del píxel central de una imagen con el de la

anterior. Dado existe cierto ruido en la imagen, aún en

dos imágenes representando la misma escena los valores

exactos de los pixels cambiarán ligeramente. Esto

significa que para detectar el movimiento no basta con

ver si los píxeles son iguales. Lo que haremos será medir

la distancia Manhattan entre ellos y compararla con un

umbral que fijaremos empíricamente. Notificaremos que

ha habido movimiento cuando este umbral se supere.

Para evitar falsas alarmas conviene tener un umbral

elevado, sin embargo esto tiene el inconveniente de que,

en el caso de que el objeto responsable del movimiento

sea del mismo color que el fondo, este movimiento

pasará desapercibido. Para reducir este umbral sin

aumentar la probabilidad de falsa alarma, usaremos el

hecho de que el ruido es independiente: Cuando se

produzca un movimiento, lo confirmaremos con los

píxeles vecinos, y sólo lo notificaremos cuando el cambio

se halla producido para todos ellos. De esta forma, el

tiempo de proceso se mantiene reducido para la mayoría

de las iteraciones.

Realizando pruebas con el terminal Nokia 6600,

establecemos que con un umbral por debajo de 80,

sobre una distancia máxima entre pixels de 256·3, se

producen falsas alarmas. En cuanto a la velocidad de

muestreo, es muy reducida. Utilizando el formato BMP,

sólo conseguimos llegar a las 2 imágenes por segundo,

que es baja para aplicaciones con restricciones de tiempo

real en general, pero para este caso puede ser suficiente

si no nos encontramos ante cambios muy bruscos.

5 Pruebas de la cámara

En este apartado vamos a estudiar las imágenes

ofrecidas por la MMAPI en el terminal Nokia 6600, en

términos de formatos, resolución, tamaño, número de

colores, y tiempo de adquisición. Este teléfono, así como

la mayoría de los de su clase, tiene una cámara VGA,

esto es, puede ofrecer fotografías de 640X480 pixels, y

esta es la resolución que podemos conseguir con la

aplicación nativa de la cámara y con programas en

Symbian. Hemos hecho medidas de tiempo y tamaño

por los tres formatos disponibles en el Nokia 6600, PNG,

BMP y JPEG (esta información está disponible en la

variable de sistema video.snapshot.encodings). Por

defecto, el método getSnapshot() devuelve una imagen

PNG de 160X120 pixels, pero se puede especificar el

formato y las dimensiones en pixels deseados. Hemos

Actas del II congreso javaHispano

29

Page 30: Actas del II congreso javaHispano

tomado medidas para cada tamaño y formato, y los

resultados se muestran en la Figura 1. También

comparamos la influencia de la complejidad de la

imagen en el tamaño de fichero: Primero, tomamos una

imagen de una pared blanca, y luego otra de una escena

compleja, con gente y diferentes objetos. Los resultados

se pueden ver el la Tabla 1.

Tabla 1: Influencia de la complejidad de la escena en el

tamaño del fichero de imagen.

Tamaño (bytes)

PNG Simple

Compleja

28953

44248

BMP Simple

Compleja

20278

20278

JPEG Simple

Compleja

1223

3469

Cuando el tamaño del fichero es demasiado grande para

el teléfono, lo que depende tanto del formato como de

las dimensiones de la imagen, hemos observado que

pueden ocurrir dos cosas: En ocasiones, la aplicación se

bloquea, y la cámara deja de estar disponible hasta que

reiniciamos el teléfono. Más a menudo, la aplicación

aborta con un mensaje tipo “Application closed Monty

Thread –7”.

Observando la calidad de las imágenes en diferentes

dimensiones, se aprecia que el teléfono siempre utiliza

imágenes del tamaño por defecto (160X120), y después

los reescala si es necesario. Por tanto, la calidad de la

imagen no mejorará.

Para aplicaciones de tiempo real, tales como el Detector

de Movimiento, podemos ver que no se alcanza una

velocidad elevada: En el mejor de los casos, nos

acercamos a dos imágenes por segundo (para imágenes

del tamaño por defecto). Los formatos más rápidos son

JPEG o BMP, con tiempos similares. Uno podría

preguntarse porqué el formato JPEG es el más rápido,

cuando es el que requiere un procesamiento más

complejo. Se da que una cámara típica para este uso

puede ofrecer varios formatos: Imágenes sin comprimir

(YCrCb) o imágenes comprimidas JPEG. De modo que la

máquina virtual sólo necesita tratar imágenes PNG o

BMP, las imágenes JPEG son creadas por hardware. Los

mismos tests han sido realizados para el Nokia 3650 y

alcanza velocidades ligeramente superiores, del orden de

siete imágenes por segundo.

Las imágenes en JPEG son las más pequeñas, y el

tamaño de fichero es poco dependiente de las

dimensiones de la imagen, y más de la complejidad de la

escena. Las imágenes PNG son mayores, pero es el único

formato obligatorio para las especificaciones de la

MMAPI. El formato BMP no usa compresión, por lo que

el tamaño de fichero es proporcional a las dimensiones

de la imagen. Sin embargo, la calidad de imagen es baja,

puesto que usa una paleta de 256 colores para (8 bits

por pixel) para evitar que el tamaño se dispare. Hay que

notar que para el tipo de aplicaciones que estudiamos, el

tamaño de fichero no es tan importante, ya que nosotros

vamos a trabajar sobre los valores RGB de los pixels,

luego en todos los casos necesitaremos un array de

longitud dependiente de las dimensiones de la imagen.

Una vez tengamos este array, podemos liberar la

memoria que ocupe la imagen. Por otro lado podemos

estar interesados en sólo parte de la imagen, así que en

cada caso debe estudiarse qué formato es la mejor

elección.

0

2

4

6

8

10

12

14

16

18

160x120 (default)200x150 320x240 400x300 640x480 800x600

TIM

E (

sec.

) ->

IMAGE DIMENSIONS ->

PNGBMPJPG

0

100

200

300

400

500

600

700

800

160x120 (default)200x150 320x240 400x300 640x480 800x600

FIL

E S

IZE

(K

B)

->

IMAGE DIMENSIONS ->

PNGBMPJPG

Actas del II congreso javaHispano

30

Page 31: Actas del II congreso javaHispano

Figura 1: Tiempo de adquisición (arriba) y tamaño de

fichero (abajo) para diferentes tamaños en los formatos

de imagen disponibles.

Algunos de los aspectos que hemos descubierto sobre el

funcionamiento de la MMAPI de Java pueden explicarse

conociendo el acceso a la cámara en lenguaje nativo. En

Symbian, el acceso está basado en imágenes, no en

video. El viewfinder debe implementarlo el programador

en cada aplicación concatenando imágenes

periódicamente. Las imágenes se obtienen usando un

esquema de objetos activos, y en un formato específico

de java, que posteriormente puede convertirse en el

formato deseado. Uno de los parámetros de la petición

de la imagen es la calidad, que puede ser alta o baja.

Una imagen de baja calidad (llamada snapshot), es

QQVGA, es decir, de dimensiones 160X120 pixels, y de

4096 colores (12 bits por pixel). Una imagen de alta

calidad es VGA (640X480) y de 16 millones de colores

(24 bits). Típicamente, las snapshots se usan para formar

el viewfinder y video, y las imágenes VGA para la

fotografía propiamente dicha. Además, el programador

puede elegir entre dos perfiles de iluminación, noche y

día, lo que modifica el brillo de la escena por medio del

balance de blancos.

Con esta información, podemos inferir que el MMAPI

crea el flujo de vídeo por medio de snapshots tomadas

periódicamente, y los pasa a la aplicación. Las imágenes

obtenidas con getSnapshot() son simplemente uno de

estas snapshots, reescalada y con un formato diferente si

es necesario. Por tanto no podremos acceder desde un

MIDlet a la calidad de imagen que la cámara puede

ofrecer.

6 Velocidad de operaciones y memoria

Para implementar aplicaciones de tratamiento de

imagen, nuestro terminal debe ser capaz de ejecutar

algoritmos pesados rápidamente, en ocasiones en

tiempo real, y también necesita almacenar la

información de los píxeles de una o varias imágenes.

Según esto, la velocidad de las operaciones y la memoria

dinámica disponible son características claves para

nuestros objetivos.

6.1 Velocidad de operaciones

Primero mediremos la velocidad de operaciones básicas

del procesador, y podremos ver cuáles son más rápidas y

cuáles deben ser evitadas al programar. Sólo nos

referimos a operaciones de bajo nivel: extracción de una

variable de un array, suma de dos variables,

desplazamientos lógicos, etcétera. Sólo hablaremos de

este tipo de operaciones porque son las que hay

disponibles en J2ME.

Para medir tiempo, J2ME ofrece el método

System.currentTimeMillis(), que tiene una precisión de

milisegundos. Lo que haremos será repetir la operación a

medir en un bucle, restar el tiempo de un bucle vacío, y

dividir por el número de iteraciones. Hemos

implementado un programa que realiza estas medidas y

muestra el resultado por pantalla. Las medidas estarán

distorsionadas por otros procesos concurrentes del

teléfono, como la lectura de eventos de teclado u

operaciones relacionadas con el servicio telefónico. De

hecho, si durante la ejecución del programa presionamos

teclas repetidamente, se aprecia un incremento del

tiempo. No intentaremos evitar estas distorsiones,

simplemente tomaremos varias medidas y calcularemos

la media. Los resultados obtenidos se muestran en la

tabla 2.

Con estos resultados podemos inferir que la división

debe ser evitada en la medida de lo posible, y que no

debemos abusar de la multiplicación, debiendo sustituir

ambas por desplazamientos lógicos cuando sea posible.

Vemos que, sorprendentemente, las comparaciones son

también lentas, incluso más que la multiplicación El

acceso a una variable de un array es más lento que una

suma porque usa indirección.

Hay que decir también que las operaciones deben usar

números enteros. Si es necesario utilizar decimales, lo

adecuado es recurrir a la llamada aritmética de punto

fijo, que permite cálculos decimales usando tipos

enteros.

El teléfono Nokia 6600 utiliza un procesador ARM de 32

bits a 104 MHz, lo que hace un ciclo de reloj de

aproximadamente 10 nanosegundos. Típicamente, una

operación simple de procesador tarda dos ciclos de reloj,

esto es, 20 nanosegundos, lo que nos deja cerca del

tiempo medido para las operaciones más rápidas.

Actas del II congreso javaHispano

31

Page 32: Actas del II congreso javaHispano

Esto nos podría hacer pensar que, si las operaciones van

a la velocidad del procesador, entonces un MIDlet

correrá tan deprisa como una aplicación Symbian, lo cual

no parece lógico. La explicación es que la máquina

virtual del Nokia 6600, llamada Monty 1.0 VM, utiliza un

esquema de compilación dinámica. Esto significa que la

máquina virtual tiene, además de un interprete (que

ejecuta bytecodes de Java), un compilador (que convierte

bytecodes en código nativo).

El código nativo es alrededor de un orden de magnitud

más rápido que el interpretado, pero ocupa pero ocupa

más memoria. La Monty VM soluciona esto con un

bloque más llamado Profiler, que identifica, en tiempo

de ejecución y mediante métodos estadísticos, partes del

código que el MIDlet ejecuta a menudo y repetidamente.

Estas partes del código se denominan hotspots. Cuando

el profiler identifica un hotspot, éste se compila de

forma que las siguientes veces que el MIDlet llame a esta

parte del código se pueda ejecutar directamente en

código nativo. El resto del código, accedido menos a

menudo, es ejecutado por el intérprete.

Tabla 2: Duración de un bucle de 10 000 000 iteraciones

y de una sola operación. Promedio de diez medidas.

La compilación dinámica se basa en la suposición de que

los programas ocupan la mayor parte del tiempo

ejecutando una pequeña parte del código. Ésta

propiedad suele cumplirse con el software en general, y

en las pruebas que acabamos de realizar en particular.

También se da que los algoritmos de procesamiento de

imagen son frecuentemente iterativos, con lo que la

suposición se cumplirá también para las aplicaciones

bajo estudio. Esto significa que podemos esperar un

buen comportamiento de nuestros MIDlets respecto a las

aplicaciones nativas.

6.2 Memoria dinámica

A continuación hablaremos sobre la memoria dinámica

de la que disponemos. La memoria volátil que se dedica

al almacenamiento de objetos Java se denomina heap.

Según las especificaciones, el Nokia 6600 dispone de una

heap de 3 Mbytes. Para comprobar esto, utilizamos una

aplicación nativa llamada Fexplorer, que permite navegar

por los archivos del teléfono, así como saber la memoria

libre del dispositivo. Con esta aplicación descubrimos

que la memoria dinámica libre, independientemente de

los datos almacenados en la memoria flash, es de 10

Mbytes. Sin embargo, la heap podría ser menor al ser la

memoria disponible para MIDlets.

Para comprobar esto, y tomar medidas reales,

implementamos una MIDlet que intenta reservar

memoria del tamaño que se le especifique. La

ejecutamos varias veces con tamaños crecientes, y vimos

en qué punto aparecían excepciones del tipo Out of

Memory Error. Si la memoria se reserva nada más iniciar

la aplicación, alcanzábamos los 700 kilobytes. Sin

embargo, si esta memoria se liberaba y se reservaba más

sin salir de la aplicación, y se incrementaba esta cantidad

poco a poco, alcanzábamos varios megabytes, por

encima de la heap indicada en las especificaciones del

teléfono.

Con estos experimentos, podemos concluir, primero, que

la heap que puede alcanzar un MIDlet es de 10

Megabytes, y no de 3. Y segundo, que la memoria

asignada a un MIDlet es dinámica: inicialmente, la

máquina virtual permite una pequeña cantidad, pero

cuando la memoria realmente usada por el MIDlet se

acerca al límite, se le asigna más.

7 Lo que podemos y no podemos hacer

Una primera conclusión es que la primera acción a

realizar al abordar una aplicación de este tipo, es

identificar los recursos de que disponemos desde J2ME,

ya que pueden no ser los mismos que desde una

Operación Duración

bucle (ms)

Una operación

(ns)

Bucle vacío 1 372.0 0.0

Extracción de un

array

2 062.7

69.1

Incremento

(++)

1 573.3 20.1

Suma 1 565.9 19.4

Desplazamiento

lógico

1 562.5

19.1

Multiplicación 1 862.6 49.1

División 12 396.7 1 102.5

Menor o igual 2 375.1 100.3

Menor 2 351.4 97.9

Igual 2 554.8 118.3

Actas del II congreso javaHispano

32

Page 33: Actas del II congreso javaHispano

aplicación nativa o que los que permitiría el hardware

del teléfono: que el terminal tenga cámara no significa

que sea accesible desde Java, y que ésta sea VGA no

significa que podamos sacar fotos de 640X480, etcétera.

De acuerdo con los resultados obtenidos, el límite mayor

lo impone la cámara, o más exactamente, las imágenes

que ofrece la MMAPI a los MIDlets. El pequeño tamaño

de las imágenes, combinado con la falta de un

mecanismo de enfoque, que impide tomar fotografías

nítidas de objetos a menos de 20 cm de la cámara, hace

difícil implementar aplicaciones como lectores de

códigos de barras, reconocimiento de texto, etcétera.

Con una aplicación nativa podemos alcanzar una mayor

resolución, aunque el problema del enfoque sigue

presente.

Si nuestra aplicación necesita procesado de tiempo real,

de nuevo J2ME ofrece muy pobres prestaciones,

mientras que Symbian ofrece una velocidad de muestreo

que bastará en la mayoría de los casos.

Si las aplicaciones tienen suficiente calidad y velocidad

con lo ofrecido por la MMAPI, encontrarán el límite

impuesto por la velocidad de operaciones, y también con

la reducida API de matemáticas ofrecida por MIDP.

Respecto al primer punto, según discutimos antes se

puede esperar un comportamiento razonablemente

similar entre aplicaciones Symbian y J2ME. Respecto a las

funciones matemáticas disponibles, aunque en Symbian

disponemos de todas las funciones que podamos

necesitar, así como tipos double para cálculos decimales,

etcétera, el programador debe evitar todo esto si quiere

una aplicación eficiente. Lo correcto será implementar

las funciones que necesite mediante otras técnicas como

tablas de lookup, aritmética de punto fijo, etcétera, que

también son aplicables en J2ME.

Por último, las aplicaciones que hagan uso del color y la

luz de la imagen, como nuestro lector de colores,

encontrarán su límite en el balance de blancos de la

cámara, que no podemos controlar ni conocer su estado.

En Symbian el problema sigue presente, aunque

podemos escoger el perfil de iluminación más adecuado

para la aplicación.

Por supuesto, la mayoría de estas limitaciones serán

superadas por los nuevos terminales que están

apareciendo al escribirse estas líneas, con mejores

cámaras, no sólo en términos de resolución, sino

también con zoom óptico, autoenfoque, flash, etcétera,

y sobre todo , con mejores implementaciones de la

MMAPI que permitan obtener el máximo provecho de las

características de la cámara. Sin embargo, incluso con las

capacidades de los terminales estudiados, pueden

implementarse aplicaciones novedosas y útiles mediante

un diseño cuidadoso y una buena dosis de creatividad.

Referencias

[1] Especificaciones del terminal Nokia 6600. Forum Nokia http://www.nokia.com/nokia/0,8764,33211,00.html.

[2] Especificaciones del terminal Nokia 3650. Forum Nokia http://www.nokia.com/nokia/0,8764,2275,00.html.

[3] Programming Wireless Devices with the Java 2 Platform, Micro Second Edition. Roger Riggs (Editor), Antero Taivalsaari, Jyri Huopaniemi, Mark Patel, James VanPeursem and Aleksi Uotila. Addison-Wesley Pub Co; 2 Edition. June 2003.

[4] Brief Introduction to the Mobile Media API. Forum Nokia, Version 1.0. 2003.

[5] Nokia UI extensions for Nokia MIDP Platform. Forum Nokia, Version 1.1. 2002.

[6] Developing Series 60 applications: a guide for Symbian OS C++ developers. Leigh Edwards and Richard Barker. Addison-Wesley. 2004.

[7] The Project Monty Virtual Machine. Sun Microsystems White Paper. 2002.

[8] What Color Is Your Pair of Shoes? A Review of Two Color Identifiers. Deborah Kendrick. Access World, vol. 5, no. 3, May 2004. http://www.afb.org/aw.

[9] Pattern Recognition. Sergios Theodoridis y Konstantinos Koutroumbas. Academic Press, 1999.

Actas del II congreso javaHispano

33

Page 34: Actas del II congreso javaHispano

Actas del II congreso javaHispano

34

Page 35: Actas del II congreso javaHispano

Programación de dispositivos Bluetooth a través de Java

Alberto Gimeno Brieba [email protected]

Abstract

En este documento se trata la programación de dispositivos

Bluetooth con Java mediante el API desarrollada por el JCP

y especificada en el JSR-82.

Keywords: Java, Bluetooth, J2ME, JSR-82, móviles.

1 Introducción

Bluetooth es una tecnología de comunicación

inalámbrica, al igual que la tecnología Wi-Fi o los

infrarrojos. A diferencia de la primera, Bluetooth está

diseñada para dispositivos de bajo consumo y para

conexiones de corta distancia (10 metros). A diferencia

de los infrarrojos, Bluetooth es omnidireccional y tiene

un mayor ancho de banda (hasta 11 Mbit/ segundo).

Bluetooth es, pues, una tecnología ideal para la conexión

de dispositivos de bajas prestaciones (móviles, cámaras

de fotos, auriculares manos libres, impresoras,…).

Uno de los mayores ámbitos de utilización de Bluetooth

es sin duda los teléfonos móviles. Cada vez es más

común encontrar terminales móviles con soporte para

Java y Bluetooth y simplemente es un paso natural que

surja la necesidad de programar estos dispositivos a

través de Java. Desde el JCP se ha desarrollado un JSR

que cubre esta necesidad. Se trata del JSR-82 que será

explicado en este documento.

2 El JSR-82

El JSR-82[1] especifica un API de alto nivel para la

programación de dispositivos Bluetooth. Depende de la

configuración CLDC de J2ME, y se divide en dos

paquetes: javax.bluetooth y javax.obex. El primer

paquete provee la funcionalidad para la realización de

búsquedas de dispositivos, búsquedas de servicios y

comunicación mediante flujos de datos (streams) o

arrays de bytes. Por otro lado el paquete javax.obex

permite la comunicación mediante el protocolo OBEX

(OBject Exchange); se trata de un protocolo de alto nivel

muy similar a HTTP.

3 El paquete javax.bluetooth

Primero abordaremos la programación de un cliente y

más tarde veremos cómo programar un servidor.

3.1 Clientes Bluetooth

Un cliente Bluetooth deberá realizar las siguientes

operaciones para comunicarse con un servidor

Bluetooth:

• Búsqueda de dispositivos

• Búsqueda de servicios

• Establecimiento de la conexión

• Comunicación

El punto de partida es la clase LocalDevice que

representa el dispositivo en el que se está ejecutando la

aplicación. Este objeto es un singleton y se obtiene

mediante LocalDevice.getLocalDevice(). Este objeto

permite obtener información sobre el dispositivo: modo

de conectividad, dirección bluetooth y nombre del

dispositivo.

El primer paso que debe realizar un cliente es realizar

una búsqueda de dispositivos. Para ello deberemos

obtener un objeto DiscoveryAgent. Este objeto es único y

se obtiene a través del objeto LocalDevice.

DiscoveryAgent da =

LocalDevice.getLocalDevice().getDiscoveryAgent();

El objeto DiscoveryAgent nos va a permitir realizar y

cancelar búsquedas de dispositivos y de servicios. Y

también nos servirá para obtener listas de dispositivos ya

conocidos. Esto se lleva a cabo llamando al método

retrieveDevices(). A este método se le debe pasar un

argumento de tipo entero que puede ser:

Actas del II congreso javaHispano

35

Page 36: Actas del II congreso javaHispano

• DiscoveryAgent.PREKNOWN. Para obtener una

lista de dispositivos encontrados en búsquedas

anteriores.

• DiscoveryAgent.CACHED. Para obtener una lista

de dispositivos “favoritos”.

El método retrieveDevices() devuelve un array de objetos

RemoteDevice. La clase RemoteDevice representa un

dispositivo remoto y tiene métodos similares a

LocalDevice que, recordemos, representa al dispositivo

en el que se ejecuta la aplicación. Así pues, podemos

obtener el nombre del dispositivo mediante

getFriendlyName() y su dirección bluetooth mediante

getBluetoothAddress().

Podríamos omitir la búsqueda de dispositivos y pasar

directamente a la búsqueda de servicios en caso de que

deseásemos conectar con alguno de los dispositivos

pertenecientes a alguna de estas listas. Sin embargo lo

más común será intentar conectar con un dispositivo

encontrado en una búsqueda de dispositivos, debido a

que obviamente lo tendremos a nuestro alcance.

Una búsqueda de dispositivos se inicia llamando al

método startInquiry(). Este método requiere un

argumento de tipo DiscoveryListener. DiscoveryListener

es una interfaz que implementaremos a nuestra

conveniencia y que será usada para que el dispositivo

notifique eventos a la aplicación cada vez que se

descubre un dispositivo, un servicio, o se finaliza una

búsqueda. Estos son los cuatro métodos de la interfaz

DiscoveryListener:

• deviceDiscovered()

• inquiryCompleted()

• servicesDiscovered()

• serviceSearchCompleted()

Los dos primeros métodos son llamados en el proceso

de búsqueda de dispositivos. Los otros dos son llamados

en procesos de búsqueda de servicios.

Cada vez que un dispositivo es encontrado se llama al

método deviceDiscovered() pasando un argumento de

tipo RemoteDevice.

Una vez que la búsqueda de dispositivos ha concluido se

llama al método inquiryCompleted() pasando como

argumento un entero que indica el motivo de la

finalización. Este entero puede valer:

• DiscoveryListener.INQUIRY_COMPLETED si la

búsqueda concluyó con normalidad,

• DiscoveryListener.INQUIRY_TERMINATED si la

búsqueda ha sido cancelada manualmente o

• DiscoveryListener.INQUIRY_ERROR si se produjo

un error en el proceso de búsqueda.

Ya hemos conseguido dar el primer paso para realizar

una conexión cliente. El siguiente paso es realizar una

búsqueda de servicios. Antes de seguir deberemos

comprender ciertos conceptos.

Una aplicación cliente es una aplicación que requiere un

servidor para que le ofrezca un servicio. Este servicio

puede ser: un servicio de impresión, un servicio de

videoconferencia, un servicio de transferencia de

archivos, etc. En una comunicación TCP-IP un cliente se

conecta directamente a un servidor del que conoce el

servicio que ofrece, es decir, conocemos a priori la

localización del servidor y el servicio que nos ofrecerá;

sin embargo un cliente Bluetooth no conoce de

antemano qué dispositivos tiene a su alcance ni cuáles

de ellos pueden ofrecerle el servicio que necesita. De

modo que un cliente Bluetooth necesita primero buscar

los dispositivos que tiene a su alcance y posteriormente

les preguntará si ofrecen el servicio en el que está

interesado. Este último proceso se denomina búsqueda

de servicios y es el siguiente paso que un cliente debe

realizar.

Cada servicio es identificado numéricamente. Es decir, a

cada servicio le asignamos un número y para referirnos

a dicho servicio usaremos su número asociado. Este

identificador se denomina UUID (Universal Unique

IDentifier). Adicionalmente, cada servicio tiene ciertos

atributos que lo describen. Por ejemplo un servicio de

impresión podría describirse por diversos atributos

como: tipo de papel (dinA4, US-letter,…), tipo de tinta

(color, blanco y negro), etc. Los atributos también están

identificados numéricamente, es decir, para referirnos a

un atributo usaremos su número asociado.

Las búsquedas de dispositivos también se realizan

mediante el objeto DiscoveryAgent. Concretamente

usaremos el método searchServices() al que le

tendremos que pasar un objeto DiscoveryListener que

recibirá los eventos de la búsqueda, el dispositivo en el

que realizar la búsqueda (un objeto RemoteDevice que

normalmente obtendremos en la búsqueda de

dispositivos), los servicios en los que estamos

interesados, y los atributos que queremos conocer sobre

Actas del II congreso javaHispano

36

Page 37: Actas del II congreso javaHispano

dichos servicios (tipo de papel, tipo de tinta, etc). Por

ejemplo un cliente que esté interesado en un servicio de

impresión, para imprimir un texto probablemente sólo le

interese conocer el tipo de papel, sin embargo si

queremos imprimir una imagen estaremos también

interesados en si soporta o no tinta de color.

Si se encuentra algún servicio se nos notificará a través

del objeto DiscoveryListener mediante el método

servicesDiscovered(). Se nos pasará un array de objetos

ServiceRecord que encapsulan los atributos de servicio

que solicitamos al invocar la búsqueda. Los valores de

estos atributos de servicio son objetos DataElement.

Un objeto DataElement encapsula los tipos de datos en

los que puede ser representado un atributo de servicio.

Estos pueden ser: números enteros de diferente longitud

con o sin signo, cadenas de texto, URLs, booleanos, o

colecciones de DataElements.

Un ServiceRecord es, pues, como una tabla que

relaciona los identificadores de los atributos con sus

valores (objetos DataElement).

Cuando finalice la búsqueda de servicios se nos

notificará mediante una llamada al método

serviceSearchCompleted() de la interfaz

DiscoveryListener. Se nos pasará un argumento de tipo

entero indicando el motivo de la finalización. Este

entero puede valer:

• SERVICE_SEARCH_COMPLETED: la búsqueda ha

finalizado con normalidad.

• SERVICE_SEARCH_TERMINATED: la búsqueda

ha sido cancelada manualmente.

• SERVICE_SEARCH_NO_RECORDS: no existe la

información solicitada.

• SERVICE_SEARCH_ERROR: finalizó por un error.

• SERVICE_SEARCH_DEVICE_NOT_REACHABLE: el

dispositivo no está a nuestro alcance.

Estas constantes son miembros de la interfaz

DiscoveryListener.

Si hemos encontrado algún servicio que nos interesa

pasaremos al siguiente paso: abrir la conexión.

Abrir una conexión Bluetooth se lleva a cabo de la

misma forma que se abre cualquier otro tipo de

conexión en CLDC: a través de la clase

javax.microedition.Connector. Usaremos su método

open() y le pasaremos una URL que contendrá los datos

necesarios para realizar la conexión.

No necesitaremos construir la URL a mano ya que el

objeto ServiceRecord posee un método que nos ahorra

esta tarea: getConnectionURL().

Llegados a este punto debemos saber que tenemos dos

formas diferentes de comunicación: a través de flujos de

datos utilizando el protocolo SPP (Serial Port Profile) , o

bien a través de L2CAP enviando y recibiendo arrays de

bytes. La forma más sencilla es mediante SPP.

Si el servidor utiliza SPP el método Connector.open() nos

devolverá un objeto de tipo

javax.microedition.io.StreamConnection. A través de

este objeto podemos obtener un (Data)InputStream y un

(Data)OutputStream. Por lo tanto ya tenemos un flujo

de lectura y un flujo de escritura por lo que estamso en

condiciones de leer y escribir datos.

En caso de que el servidor utilice L2CAP el método

Connector.open() nos devolverá un objeto del tipo

javax.bluetooth.L2CAPConnection. Con este objeto

leeremos bytes con receive() y escribiremos bytes con

send().

3.2 Servidores Bluetooth

La creación de un servidor Bluetooth es más sencilla que

la programación de un cliente ya que no necesitamos

realizar ningún tipo de búsqueda. Concretamente los

pasos que debe realizar un servidor Bluetooth son los

siguientes:

• Crear una conexión servidora

• Especificar los atributos de servicio

• Abrir las conexiones cliente

Crear la conexión servidora es relativamente simple.

Sencillamente debemos llamar al método

Connector.open() pasándole una URL con una sintaxis

determinada. En caso de querer comunicarnos mediante

SPP la URL comenzará por “btspp://” y en caso de querer

comunicarnos mediante L2CAP la URL comenzará por

“btl2cap://”. A continuación deberemos indicar

“localhost/” como host. Esto determina que no

queremos conectarnos a nadie, sino que queremos ser

servidores. Seguidamente sólo nos queda concatenar a

la URL el identificador del servicio (UUID) que vamos a

ofrecer.

Actas del II congreso javaHispano

37

Page 38: Actas del II congreso javaHispano

A continuación llamaremos al método Connector.open()

pasando la URL como argumento. Si la URL comienza

por “btspp://” nos devolverá un objeto del tipo

javax.microedition.StreamConnectionNotifier y en caso

de que la URL comience por “btl2cap://” nos devolverá

un objeto javax.bluetooth.L2CAPConnectionNotifier.

El siguiente paso es especificar los atributos de servicio.

Por ejemplo si vamos a ofrecer un hipotético servicio de

impresión podríamos indicar qué tipo de papel y de tinta

ofrecemos. Los atributos de servicio se almacenan en un

objeto ServiceRecord. Cada conexión servidora tiene un

ServiceRecord asociado que se obtiene a través del

LocalDevice.

Establecer los atributos de servicio es sencillo,

simplemente tenemos que crear objetos DataElement y

añadirlos al ServiceRecord.

Una vez establecidos los atributos de servicio ya estamos

en condiciones de escuchar y procesar las conexiones

cliente. Para ello usaremos el método acceptAndOpen().

En una conexión servidora SPP este método devuelve un

javax.microedition.StreamConnection, y en una conexión

servidora L2CAP devuelve un objeto del tipo

javax.bluetooth.L2CAPConnection. En este punto ya

podemos leer y escribir datos del mismo modo que lo

hace un cliente.

4 El paquete javax.obex

El paquete javax.obex permite manejar el protocolo de

alto nivel OBEX (OBject Exchange). Se trata de un

protocolo muy similar a HTTP. Al igual que este último,

OBEX se basa en mensajes compuestos por cabeceras de

mensaje y opcionalmente de un cuerpo de mensaje.

Adicionalmente los mensajes de respuesta del servidor

poseen un código de respuesta indicando éxito o error.

Al igual que en HTTP, los mensajes de petición del cliente

al servidor en OBEX se clasifican por métodos. Estos son

los métodos que existen.

• CONNECT. Inicia la sesión.

• PUT. Envía un archivo al servidor.

• GET. Solicita un archivo al servidor.

• DELETE. Solicita la eliminación de un archivo.

• SETPATH. El cliente desea cambiar el directorio

actual dentro del sistema de archivos del

servidor.

• DISCONNECT. Usado para finalizar la sesión.

Las cabeceras de un mensaje OBEX son encapsuladas por

un objeto HeaderSet. Existen cabeceras de uso común

como COUNT, NAME, LENGTH,… Sin embargo podremos

crear cabeceras personalizadas.

La clase Operation provee la funcionalidad para leer y

enviar mensajes que no sólo tienen cabeceras sino que

también tienen un cuerpo de mensaje. Esta clase permite

obtener un (Data)InputStream y un (Data)OutputStream

para leer o escribir el cuerpo del mensaje.

Ahora que conocemos las clases básicas pasemos a ver

cómo programar un cliente OBEX.

4.1 Un cliente OBEX

La programación de un cliente OBEX es relativamente

simple. Debemos abrir la conexión, como siempre en

CLDC con el objeto Connector. Deberemos pasarle una

URL que comience por “irdaobex://” y nos devolverá un

objeto de tipo javax.obex.ClientSession. Lo primero que

deberemos hacer será ejecutar el método connect() para

iniciar la sesión.

A partir de aquí ya podemos realizar peticiones al

servidor a través de los métodos put(), delete(), get() y

setPath(). Todos los métodos requieren un objeto

HeaderSet como parámetro. Los métodos put() y get()

adicionalmente devuelven un objeto Operation que

permite escribir o leer el cuerpo del mensaje

respectivamente.

Para cerrar la sesión llamaremos al método disconnect().

4.2 Un servidor OBEX

Crear una conexión servidora OBEX es también muy

simple. Lo primero de todo es crear un SessionNotifier

llamando al método Connector.open(). La URL debe

comenzar por “irdaobex://localhost”. Ahora simplemente

escucharemos las conexiones cliente llamando al método

acceptAndOpen(). Este método requiere un argumento

de tipo ServerRequestHandler. El ServerRequestHandler

es un objeto que deberemos implementar nosotros. Se

implementa de forma muy similar a un servlet: por cada

método del protocolo OBEX tiene un método asociado al

que se le pasan los datos de la petición. Así pues

tenemos los métodos onConnect(), onGet(), onPut(),

onDelete() y onDisconnect(). Todos los métodos tienen

como argumento un objeto HeaderSet que encapsula las

cabeceras de los mensajes, exceptuando los métodos

Actas del II congreso javaHispano

38

Page 39: Actas del II congreso javaHispano

onPut() y onGet() que requieren un cuerpo de mensaje y

por ello su argumento es de tipo Operation.

Adicionalmente todos los métodos a excepción de

onDisconnect() deben devolver un entero que será el

código de respuesta indicando el éxito o no de la

petición y su motivo.

5 Implementaciones del JSR-82

Existen dispositivos móviles que soportan Java y tienen

Bluetooth, pero sin embargo no soportan el API JSR-82.

Esto quiere decir que no tenemos posibilidad de acceder

al dispositivo Bluetooth a través de Java. Por ello habrá

que acudir a las especificaciones del fabricante para

cerciorarnos de que las APIs están soportadas.

A pesar de que el JSR-82 se especificó pensando en la

plataforma J2ME. No sólo existen implementaciones y

emuladores para J2ME. Debido a que J2ME es una

versión reducida de J2SE, es perfectamente factible crear

una implementación que pueda ser usada desde J2SE.

De hecho existen implementaciones y emuladores. La

mayoría de estas implementaciones son libres y suelen

soportar dispositivos Bluetooth conectados al puerto

serie. Otras implementaciones son bindings para Java de

las APIs Bluetooth que ofrece el sistema operativo.

Ciertos emuladores y entornos de desarrollo también

implementan estas APIs simulando dispositivos

Bluetooth, es decir, permiten realizar aplicaciones que

usen las APIs JSR-82 sin necesidad de tener físicamente

un dispositivo Bluetooth.

6 Documentación

La documentación sobre las APIs definidas en el JSR-82

es muy escasa y mucho más escasa es en español. Sin

embargo en javaHispano se publicó un tutorial[2] al

respecto en el que se puede encontrar mas información y

enlaces a otros documentos.

Por último añadir que siempre es fundamental tener a

mano la documentación javadoc de las APIs, la cual se

puede descargar desde la página del JSR-82[1] junto con

la especificación.

Agradecimientos

Agradezco su apoyo a la Escuela Universitaira Politécnica

de La Almunia, a Ángel Blesa y a todos mis compañeros

de carrera. Pero sobre todo a todos los miembros de

javaHispano por hacer esto posible.

Referencias

[1] Especificación del JSR-82: Bluetooth desde Java. http://jcp.org/en/jsr/detail?id=82.

[2] Alberto Gimeno Brieba. JSR-82: Bluetooth desde Java. http://www.javahispano.org/tutorials.item.action?id=49.

Actas del II congreso javaHispano

39

Page 40: Actas del II congreso javaHispano

Actas del II congreso javaHispano

40

Page 41: Actas del II congreso javaHispano

���� ����������� ������ ����������������� ��������������������� ������ ����������������� ��������������������� ������ ����������������� ��������������������� ������ ����������������� ����������

��������������� ����������������������� ����������������������� ����������������������� �������������

�����������������������������������������������������������������������������

�����������������

����!��"���#���� ����!��"���#���� ����!��"���#���� ����!��"���#�����

���"������������

������������������������������������

$�� ����������� ������� ��� ��� ������"%�� ������ �� ����$�� ����������� ������� ��� ��� ������"%�� ������ �� ����$�� ����������� ������� ��� ��� ������"%�� ������ �� ����$�� ����������� ������� ��� ��� ������"%�� ������ �� ����

��������� �����"����� &��'� ����������� �����"����� &��'� ����������� �����"����� &��'� ����������� �����"����� &��'� ������ ����������� �������'����� ����������� �������'����� ����������� �������'����� ����������� �������'�

����������� �� �������� ���� ���� ���������� ��� ������������������� �� �������� ���� ���� ���������� ��� ������������������� �� �������� ���� ���� ���������� ��� ������������������� �� �������� ���� ���� ���������� ��� ��������

���������� (���� ����� ����������� ����������� ����� ������������� (���� ����� ����������� ����������� ����� ������������� (���� ����� ����������� ����������� ����� ������������� (���� ����� ����������� ����������� ����� ���

���"�������#���� ������������"�������������������)�����������"�������#���� ������������"�������������������)�����������"�������#���� ������������"�������������������)�����������"�������#���� ������������"�������������������)��������

�������������������� �����&�������������� ����������������������������� �����&�������������� ����������������������������� �����&�������������� ����������������������������� �����&�������������� ���������

�������� �����������������*�� � $�� ������*� �������� �� �������������������������*�� � $�� ������*� �������� �� �������������������������*�� � $�� ������*� �������� �� �������������������������*�� � $�� ������*� �������� �� ��������

������� &��� �������� ��� ������ �� �������� ������ #� ���������� &��� �������� ��� ������ �� �������� ������ #� ���������� &��� �������� ��� ������ �� �������� ������ #� ���������� &��� �������� ��� ������ �� �������� ������ #� ���

������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

(������������������&������������������������"���������&���(������������������&������������������������"���������&���(������������������&������������������������"���������&���(������������������&������������������������"���������&���

�� ������� ������ �������� ������� ������ �������� ������� ������ �������� ������� ������ ��������� �������'� ����� ������� ����� �������'� ����� ������� ����� �������'� ����� ������� ����� �������'� ����� ������� ��

����������������*�������������������������������*�������������������������������*�������������������������������*�������������������

+���������,������ �����������������*����������'� ���+���������,������ �����������������*����������'� ���+���������,������ �����������������*����������'� ���+���������,������ �����������������*����������'� ���

���������������������������� �������������"���������������������������������� �������������"���������������������������������� �������������"���������������������������������� �������������"������

�������� �� ������ ��������� �*��� ��� ��#��%�� ���������� �� ������ ��������� �*��� ��� ��#��%�� ���������� �� ������ ��������� �*��� ��� ��#��%�� ���������� �� ������ ��������� �*��� ��� ��#��%�� ��

������������ �� �������� ���'� �������������� �� �������� ���'� �������������� �� �������� ���'� �������������� �� �������� ���'� ��� ������� ��� ����� ��� ������� ��� ����� ��� ������� ��� ����� ��� ������� ��� ����� ��

������������� &��� ���� ���� �� �� ��������� �-����� �� ���������������� &��� ���� ���� �� �� ��������� �-����� �� ���������������� &��� ���� ���� �� �� ��������� �-����� �� ���������������� &��� ���� ���� �� �� ��������� �-����� �� ���

�������� ������������������� �������������������'���%�������������� ������������������� �������������������'���%�������������� ������������������� �������������������'���%�������������� ������������������� �������������������'���%������

��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

�������������������������������������������� ����#������������������������������������������������ ����#������������������������������������������������ ����#������������������������������������������������ ����#����

�������������������������'�����������&�����.���&����������������������'�����������&�����.���&����������������������'�����������&�����.���&����������������������'�����������&�����.���&���������

������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

#� ������ ��� ����������� ����� �� �������� �� ���������#� ������ ��� ����������� ����� �� �������� �� ���������#� ������ ��� ����������� ����� �� �������� �� ���������#� ������ ��� ����������� ����� �� �������� �� ���������

/)+0$��-�/)+0$��-�/)+0$��-�/)+0$��-�����

1�#2�����1�#2�����1�#2�����1�#2����� ������'� �������'� $�������*� ��

�������'�3���������'���������������"����'�$��-�

4�����5�������*���������������������"�����4�����5�������*���������������������"�����4�����5�������*���������������������"�����4�����5�������*���������������������"���������

$��� ��������� �����"����� ��� ������������ ��

�������� ���������������������������������&���

������� ��"�������� ������"�������� ����� ������� #�

�����"��� ��� ��������*� &��� ���������

)���������� "����� ����� ���������� ����� ���

6����� �� ������ �������� �� ���� ������� ��

����������*���������/3����

.���� ��������� ��� ������� �� ���� ����� ������ ���������

����#�� �� ��&��,�� ����������� (���� �.+� ��

��������� ����� ������,��� �� ��������������

������"������������������������"������������"�����

������������� 7��� ����� ����� �� ���� ���������

�����"�����������������������������������������������

&��� ��&������ �� ����� �� � ��"����� ������������

.��� ��������� ����� #� ������� ������*���'�

����������*'� ������� �� �������'� �������� �����

�� ������� #� ���������� �� ����������� .���� &������ ���

�������� ���� ������� ��� ��� ����������� ��������

35�� ��� ���� ��������� /3��� �����'� �-�����

���������������������&��'��������������������

� ����� ��"����'� � ������� ��� �*��� ���������� ��

������������ &������ ������������&��� ��������� ���

�����������

$��� ��������� ������� �� ������������ &��� ���

�����&����������-�������������������-�*������'�

#�� ���� ���� ��� �������� �������� ���������'� ���

����������� �� ������ �� ��� ����� �� ���� ���������

�%������� 7��� ��� ���������*� ��� ��� �-�������

�������� �� �� ����������� �� �������� ��������

�. +��8�����������.�������� ����+��9������������

Actas del II congreso javaHispano

41

Page 42: Actas del II congreso javaHispano

��%�� #� �������*� �� �. +�� ��"6� ���� ���������

53:�����������������������������*����������������

.��� ��������'� ����� �������� ������� ��� ������ ��

������� �������� �����'� ��� �������� ����� ���,���

����� ��������� �%��������� ���� ������� �� ������� ��

���������&�����������

;����)������������������"%�� �������;����)������������������"%�� �������;����)������������������"%�� �������;����)������������������"%�� �����������

+�� �������� �����"���� ����� ���� ���������� ��

�����������������������������������������������3��

�����"�'� ��#� ��� ������� ����������� &���

���������� ��� ��������*� �� ��� ��&���� ��������

���������������������������"�������

.�������� ��� �����������*� �� ��������� �����"����� #�

��"������� ����"�� ��� �������� �� ������ ���������

�� ������ �� ��� ��������� (���� �� ��� ��#� ���������

������ �� ������ &��� �� ��� ��� �������� �����

���%�� �������� #'� ������ � ����'� ���� ��������� �����

�������� ���������� ����� ����� ������� ���

��������*� �� ������� ����������� .���� ����� &��� #��

����� ����� ����� � ��� ������������ �� ��� �����

�����������������

�9� +���������������������"������#����� ����

��������*� �� ���� ��������*� �� ���

�����������

�9� +� ��&����� �� ��������*� ����� ���

��������*� �� �������� ����������� ��

������������

�9� +��������������������������������������� �����

���������������������������������������

�������������������������

3�"����+�������������������������������������

����'� ���������� &��� ���� ���������� ���������� ���

���������� ��� ������� �� ������� ������� ��

���������'�#� ��������&���������������������

((.<:�'����������� ���������������������������

���������#�������������"�������(��������*������ ����

��&�����������������%�������������������������������

����������#�����������&������������������������

��������*���

=�#� &���� ����� ����� �� ��� ��� ������� ��

������������������������-�������"���������������

����&�������������������������������������������

��������"������������������#������������ �����������

��������&�������������������

�� .���� ���������� ��� ��� ��

����������������� ����� ����� ����

���� �������(��� �(���������������������������

���������*�����&�%����

�� .���� �������� ����� �� ����� (��� +��

��������*� ���%�� ������ ����� �� ���������

2��� �� �� ��� �������'� ����� �� ��� �������� ��

���������������&����������������/3����

�� .��&��� ����������� �����"��� ���

��������*� �� �� ������ ��� ��

����������� ����� ���� ���� ������� (��� +��

��������*� &��� ������� ������� �� ����

����������������������������������������

���������������������������*������

�� .��������������������������"��������������

���������� �������������������������53:��

(��� ����&����� ����� ���������� ��

����������*�#����������*��

�� >� ���&��� �� "������ ��� ��������� ������

�������� ������ �� ��� �������� (��� .������

������"��� ���� �������� �� �������� 6������

�����������������'�������������������������

�*��������������� �����������������������

���� ������

+�����������������&���&�������������������

��������*� &��� ��� �������� ����� ��� ����� �� ���

�������� �����"���� ����������� ��������*� ������

�����������'���"������'���������#�����������������

��������"����������.����

$��� ����������� ��� ����������� �������� ���������

����������� #� ���2���� ������ ��� &��� ������������� (��

��������� ��� &��� ��� ��������*� ���"������ �����

����������'��������������������������� �������

������������*����"�����������������������.�����

�������� �������"���#����������&��,���������������

�������� �������� �� ��� ��������� ������ ��������

�������������������������*����������#���

�����������"����(�����,���� ���������#��������

������� &��� �� ����� �������'� ����� ��#� ������

����������"����������������2�����������������

#�������������������������*��������������������

����������

(�������������������*��������������'����������

�����������,����������������������������.���

Actas del II congreso javaHispano

42

Page 43: Actas del II congreso javaHispano

���� ��������������&������ ���"�������������������

�������������������2����#�����2�������������&���

����������������"������(���������������'�"��������

���������������������������

������������ "������ ��� ������� ���

�������������>����&�����#�����������������%�����

�� ���"��������� ��� �-��������� �� ��� ��"�����

����� �������&��������#���%��������������������

��� �-��������� �� ���� ��������� ���������

����������������������������

?����"��������������������������"%��?����"��������������������������"%��?����"��������������������������"%��?����"��������������������������"%��

��������������������������������� ��������������������������������� ��������������������������������� �������������������������������������

��&���������������&��������������������������

������"%�� ������� ����� ������� �������� ��#�

��"�����������������������&��������������

�� (�� ������ �� �������� ����� ��#� ������"���

���� ��� �������'� �������� �� �������� #�

���������������� �������.��������������

������������������������&�������������*���

�� �� ������ �� &��� ��� ������ ������� ���

������������"����&����������������������

���'� ��� ��&���� �������� #� ��� ������ �� ���

����������� ������ ���� ��������� ��#�

�����������������������

�� >� ���� 6�����'� ����� ����� �������� ��� ����

���������'� $��� ��������������� ���������

�� ������� ������� �� ���������� �����

��������������������������������

(����6�����������������������������������������

����������������@.���&�����������A�.�����������

�������,�������� ������������������������"���

�� &������� ��� �������� #� ������� ���� ������

�����&���������������������:�&�����������������

��� ����������� ��"���� ��� ����������� �� �������� (�

����&����� ����� ��� �� ���,�� �� ��� ����� ������ ��#�

��"����������������������������������������&���

��#���%���������������BC1��������������

C�� ��������*�����������������������C�� ��������*�����������������������C�� ��������*�����������������������C�� ��������*���������������������������

3�� ������� ��� ���������*� �� ��� �����������

�������;�4�4�������������

/����"������������D�!����������

���������������"#����������&�������"����"��

�����������)������� ���������������"#�����2�

�-����������������������������'�����������2����

����E����� �������"���� �"���"��"�F����&�����

������G�����#��7��������'���������������"��������

�����������������������������������������������

����������������3����"�������������������������

2����������������#��������������

!�����������������������&������finalize() 2�������

���������#����������������������#��#����� ��������

��������������'������"��������������������#�

����������������H4I��

.�����������&������������������������'����*���

�� ��#� �� ����������� �� ������'� ���� &��� �� ��#�

�"��� ������ �������� �� ���������� ��� ��������

�������=���������������������&��������"�%�����

������������������������������ ��������������

����������2�����&���������������������*H;I���

.���� ������ ��� ��������� ������� ������� ��

����� ���� ����� ������� ��� ������� �� ����-���

����� ������������� +� ������� ����� ������

����������� �� �� ������������ ����� �� �������

����� ������ �������� �� ������� �� �������� ���

�����������(�������������������&��������������

�����&���������&����. +���������������#�����������

<����������� ������� �������� ������ C� �������

�*"����'� ��� ������ �� ��������-��� �. +3� �����

�������'�������*���������6�������������������%�����'�

���%��������� ���&����������������������������

��������������#�&���������������������-������

"����� ��� �%���� �� ��� ������� ��� �������� <����

�����'� �-����� ������������� �����������

3���"����� ����� ������������� ��� "������� ���

���������������*���� �� ��� ��������� ����'� ��������

���������������*����#����6����������� ��������

�� ���������*� ���� ������ �� � �� �������������

@��������������������������������������������������

��������A�.�������������"����5���������%�����

������ &��� ��� ������������ ��� ������ ����

�����������������"�������������������*���'�

����'� ���� �� ��"������ &��� ��"�� &��� �����������

������������������������������������������������

.��� ��� ����� ��� ����"�� �� &��� ��� &������� ���

�������� ���� ����� ����� ���� �������� �� ��� ����

����������������������������&��,����

3�����������������������������������������(����

����*� ;�;�4'� ��� ���� ���� ��� ������*� �� ��

����������� �� �������� .���� &���� ����� ���

Actas del II congreso javaHispano

43

Page 44: Actas del II congreso javaHispano

��������%������ �������'� ��� ����'� ���� �������� &���

������� ����������� �� ������� �� ��������� ��

�&����������������&����������"���������������

@����"�����A� ���������&�����������������3��

�������� &��� ��#� JKL� � ������� �� ��������� �������

������ �� ��� ����� �����'� ����%�� ���

�-����������� ��%���� �������� ����������� ��

��������� ��� ��� �����������*� �� ��� ��&����

��������;�;�4��� �����>�����������&������������*�

��������������������������"��������������������

(�����&���������'�������������*���������������������

�������������������������������#�������7�����������

������� �������� ����� ���� ��� �������� #� ��� ���� ��

������ �����'� ������� �� ������ ��������� ������

��������*�����������&���"�������.����������'����

����� �� �� ������� ������*���� �� ��� �"��� ����

���������35����(�����"������&����������������������

����� ��� ������ ��� ��� �������� ����'� ���� &���

��"���������&���������������%���������������"���

������������� ��� �������� �� �������� �� ��

�����������������������������

(�����������������������*����������������������

����� ������� 3�� �����"�� ��"���� �� ����� ���������

������������������"%��:7�4�8:����7������9�&������

����� ����������� ��������� :7�� ��� �� ������

���������������������������. +3�������������

�*���'�#������/3�'�/.<3���+�73��

=����� ������ ��� ����� �� ������ ���*� ���'� �����

@=����� &��� ����� ���������� �� ��������� ����� ���

���"������� ��� ������������ �� ������� �������A�

M��������"�����������

�� ����� ���� �������� ����� ���� �������� ���

����������#��������������������������

�������� ��������� �� ��� ���������� ���

������ �� ��� ������ ��������� (�� ����� ���

����"����� �� ��� ������� �� &��� ��������

��������������������������������������'������

&��� �� ����� ����� ��� ������� �� "�����

����������BC�1��� �����������������������

������� ����� &��� ��� ��������� ��������

��������������������������������#��������

����� ���� ������ ����� ��� ������ ��

����������������

�����������������������������������������������������������

4�(��������:7���������� ���������������������&���������������

�����������������������2������������ �����������"��������"���

�� $��� ��������������� ����������� ����

����������������&�������������������

�������������������� ������������&�����

������ &��� ������#�� ���������� �� ������

��� ����������������� �����������&���

����"�������������������������������������

�� (����#���������&���������"������� �������

����"��� �� ����������� ����������� .��� ��������

�������������������#�"�������#�����������

��������� ����� ������� �� ������ #� ���"��

����� ������ ������� )�� ��� ���"���'� �����

��������������"������*����������������'�

����� ��� ���"������� ��� ���� &��� ��

����������������������

�� =�#�&�����������#������������������-����

&�����������������������������$�������������

����,�����������&������������#�����������

��������� �����-������ ������&��� �*��� ���

������#�����6���������>'�����������'���

�������������������,����

�� 3��&�������������N���"����������������*�

�� ������ ��������� �� ������� ��� ����� N�

��"������� #� �������� ������� &��� ����

���������%��� ��� �������� ��� �������� (� ���

����� �� ���� ������ ������ ��������� ��

������� ��������� #� ������� ���� ���� &��� ���

���������������*���

<���� ���'� ��� ������������ �� ���������� ���

�������� ��� ���� ��� ���� ��� �����"����� &��� �����

������������������#�������������������������%������

���� ���"��������� ������� &��� ����� &��� ��������

���������������"������*��

�����'� ������� ����� �� ������ &��� ��� ��������

����������������������������<:�'�((.<:��#�<����

$��<��������#���������������#������������3�������

����&����� ��"������� &��� ��&������ ���������

���������� ���������� � ����� ������������� ������ +��

��������*� �%����� ����� ��������� &��� ��� ���������

������<��������������������������������������'�

����'� ��� ���� ���� ����� ���� ����������� �����

"��������������������((.<:��#��������������������

<��� ����� ������ ������������� 7��� ����� �����'� ���

���������&��� �*�����#����������� �����������#'�

������ �� ������ &��� �*��� ��#� C1�� �� <���

������������������������������������

Actas del II congreso javaHispano

44

Page 45: Actas del II congreso javaHispano

C��3�����*�&�������������C��3�����*�&�������������C��3�����*�&�������������C��3�����*�&�����������������

M����� �� ��������������� ���������� &��� ���� ����

���������� �������� ����� �������� ��� ��������

������*����������������������������� ����� � +�

������� ����� ��������� ��� ������ �� ��������

����������#���������������������������������������

���������������������������������������$��6����&���

��#� &��� ������ ��� &��� ������ �� ��������

&�������� ��������� #� ����� ������� �������� �� ���

��������*�� $��"�� ���� ������� ����� ���������� #�

���������� ����� &������� (�� �������� &��� �����

��"���� ������������ ����� ���������� ���

��������"�'� ����'� ����� &���� �� ��� ������*� ���

���"������� ����� ��� �������� ���������� �����

���������������������#��������������������������

�����������(�����&���������'�������������������

�� ������ &��� ��� ��������� �� �������� �� ���������

�����&���������"���������&��������������*��������

�������"�������������*�������������

K�)����������,���K�)����������,���K�)����������,���K�)����������,�������

(���������&������������*����������������������

�������"�������#����#����#�������������������

����������.���'����"6����������������������

��� ���������� �� ����� ����#� ������� &��'� ��� �������

���%�� ������� �� ��� �������� �� ������ ���������

7��������������������#�������������#��������

���&��'��������%����� �����������������������

���� ����#�� .��� ��� ����'� �������� &��� ����� ���

��������*�������������������������������

$�� ����������*� ���� �� �������� ��#� ����������

)���������� ���� �������� &��� &������ ����������

������������������������������������8����5 9�#���

���������������������"6���"������#��������

����%�������"������������ �������(����������

��� ��#� ��"���� ������� &��� �� ������� �����

��"��������� ��� �� �5 � ������� (���� ��� �� ���������

���&��� ����&������ &��� ����"�� ��� ������ �����

������ ������ �,��� .��� ����� ���� �� �������

���� �������&�����������&�������������#�����#��

&��� ������ ���� ����������� ����������� ��

������"���%��� $�� ������*� &��� ������ ������� ���

��#��������������������'���������������������

���� ��"��������� ������ ��� ���������� �� ��

��&��,�� ������� ��� &��� ����������� ������� �*��� ���

������ ������� ������ &��� ����� ������� ����"��

�������������������������������������������������

����������&������ ��������������������� ����������

����������������������������

3�������"�������������������������������������

��"��������� ��������� )��������������� ���������

�������#��������������������,�����������������

������������(�������������������������� �����*�

���������'������������((.<:����������������

����� �� ���������� .��� ���� ���*� �������������

� ��� ����� ���� �&������ &��� ��&������ �������� ��

����������������������������������������*�����

��"��� �� ����� �� ��� �������� ����������

7������������� ��� ������� ����� ����������

���������� ��"����*'� ��"������*� #� ��"������*�

��"����� (�� ��������� �� ��� ��"������*� ��� &���

������� ���"������*� �-����� &��� ��� ����"�� ��

���������� �������� ��"����'�&���������������&���

�������� �������� (���� ��� ��"����*� #� ���

��"������*���"������������*������������������

$����"����*���������������������������������

��&������ ����� ���������� (�� ��������� ��� &��� ���

��"������*���"���� ������ �����������������

��������������2���������������&��������������

�����������������������������2�����������������*����

�������#��������������������������%�����'��������

����"�����������������"������*���"���'����

�������� ���� ��� ��"����*� ����� ������ ��

��"������*����������������

$��� ���"������ �� �������� ����� ���������

������������������ �����&����������������

���� ���������������&����������������������&���

��&������ ���� �� ��� ��"��� ����� �����

���������� &��� ����� ����� ������� ��� ������

��������� �������� (� ������� ���� ���� ���

����������"��������������������������������

�� ��������� �����'� �� ���� ����� ��� ����������

��������������������*��������

�� .��� ���������������#�����������

�� +�����������"������

�� +���������������������������������

Actas del II congreso javaHispano

45

Page 46: Actas del II congreso javaHispano

(���������������� ����������#���������#�����������

B������<O�����������+�-���

(�� �������� �� "������ ���� ���� &��� ���� �������� ��

�������� ��"�� �� ��,�� #� �� "������ ������ ��

�������� �� "������ �� �� �������� �� �������

���������� �� ��� ��������� :���� ������ ���%�� �����

������� ������� ��������� #� ���������� ���� ������� ���

������� �� ��������*� &��� ��� ����� �������� #�

�������������������&�������

(����������������������'�������������������������

�������������������������������������������#������

�����������&����&�����������������������������

������������������ �����������

B��.5�����*�������������B��.5�����*�������������B��.5�����*�������������B��.5�����*�����������������

.������������������������������������������

"�������

4�� 5����������� �� ������*� #� ���� ����*� ��

����������

!���*���"������#����"����������������������������

�������� #� ������ #� ��� ����� ����� ���� ���������

�-����������*����������������

;��5��������������������������������

$����&�������������������'�����'�#���������������'��

����������������"����������"��������������'�

#��������������������������������������������

#� ����� ��� (���� ��� ��%� ���&��� ���������� &��� ���

((.<:�������#������������������.��������������'�

������"����'�������������������������

?��5���������������������#������������

5������������������#�����������#���#��������7������

��� &��� ������ �� �����#� ��������� ����� ��������

��������"��������#��"������

C��:������������������������� �����#�"�������

���2'�����'�������#����� ����"����������������

����������%�������������������

K��:������������������������������������

������� ��� ���� ��� ���������� ����'� �������

���� ����'� ������� ��� 6����� �� ��������� �� ���

���������'� ������� �� ������ �����'� ������� ��'�

��'��E���#�������������������������������������

&��� ������'� ��������� #� ������ ��� ������ �� ��

��������

B�� :���������� ������������ ��� �������� #�

���������������������*��

:������ ��� �������� ������ #� ��� ������� ��%� �����

�#���������������*�

J�(���������������� ����J�(���������������� ����J�(���������������� ����J�(���������������� ��������

5���������������������������������������������

�����������������.5�&��������������-��������+��������

����&������ ����� ����� ��� ������ �� ���� ���������

.������������������������������������������8�5 9�

����*����������������

+�� ���� ��� ��� ������ �� ��� 5������'� ��� �������

������� ����� ������� �� ���� ������� ������ ���� &���

����� �������� ����������� �������� ��� ��������'� ���

������������������������������� ������3*��������

������ ��� ������� �����'� ��"��������'� #� �� ������� ��

������� ����������#�������� �������������������3��

�������� ����� ��� �������� �� ����� ������� ����� �����

&���� ��� ���� ���� �������� (���� ��� ����� ������

������ "������ #� ���"��� ���� ���� �����

��������������� �����������������������������

�����������#��������������������������

N����������*��������-������N����������*��������-������N����������*��������-������N����������*��������-����������

+�� ���� &��� ������� �� ������� ������ �� ��������

�������������������#��������������������������

����-���������(����������������������������������������

&��� ��"�� &��� ����������� �. +3� &��� ��� ���"��'�

��������� ���� �������� �. +�� �� ���������� ��� ���

��������*�����������(������������������������

���"������*�� � ��"���� ������������ &������

����"������������ ��������"�������������. +3���

�����'� ����� �-����� ��� ������ ������ ��

������������������&��������������������������

�������� �� ��� ��������� .��%����� ����� ����� �*����

�� �������� ��������� ����� ��� ������������ ��� ��������

����������������&���������%������������������

������ ��� ����� ���� 7������ ��� �������� &���

���� ���� ��������� #� ����� ����� �� ������ ��"���� #�

Actas del II congreso javaHispano

46

Page 47: Actas del II congreso javaHispano

������������� ��� ��� ������� �� �� ����� &���

���"�������������������������������

.���� ��"���� &��� ����� ������� ��"���� ����� &���

������ ���"������ �� �*���� �� �������������

&����������"�������������������������#�����������

�� ��� �.5� �� �. +��� (��� � ����� ������� �������� ���

�����������������"����&�������&������������������

$�� 6���� ��������� ��� &��� ���������� ��������

����������������������������������������������

���������� ���� ������������� �� ��������� ��

����������*� ����� &��� ��� �*���� ��

���������������������������������#��������������

�������������������������.���'�����������'������#�

��"�� &��� ���� ��������� ������� ����� ������ ���

������������������������"�������

+�� ���� ������������ ��� ���������� ��

������������� ������� �. +�'� ��� ���"����� ���

�������� ��� ���� �������� ��� �*���� �� �������� #�

������������'� ����&������ ����� ������� ����� ���

�������� ����� �� ����������� �� �������� ������

�����'�������������������� ���������������������

�������� �������� #� �� �������� ���� ����� �����������

����� ���"��� �� �������� (�� �������� ����� ��������

����� ���� �. +�� ���������� ����� ��"��������'�

���������#������������������������

@>�&���������������������A���������������(����

�����������'������������������������������������

�� ��������� ����� ��&���� /)+� 0� $��-� &��� ���� ���

�����������*������������������������������

����� ������ &��'� ����� ���'� �������� �� ������� ��

���������� +� ��������� ��������� ��� &��� ����

������������ ����� ���,���� ����� �� ������� ��

��������� .��� ���� ��� ����������� ������� �� ���

��������������������������*�&�����������������

����� ��� ���������� .�3�� $���;'� ��� �����*� �������

���������?�.�3����������������

P�(�����������������*P�(�����������������*P�(�����������������*P�(�����������������*����

3���"����� &��� &�������� ������ ��� ��������*�

&������������"������������,����������������35��

����*�������������*������#����� ���������������

&������ ����������� ������ ��� ��"���� �����������

�����������������������������������������������������������

;�.����������������*�������.�3��$�������������

�����00�����������������������"0�

?�$��������������*���.�3������������������

�����00222�����2��E"��������0�

&�������� &��� ��� �������� �� �*���� ��� ��"��

������������� �������������

(�����������&�����������������������

�9� .�����������������������������,��������

�������������������*������

�9� .����"���������������������������������

���������'�&�����������*����#�������

"�����������������

�9� Q��� ����� ��� ������� ;C� ������ ����� ��

�����������,����

.������� ��������������������*��������������������

�����������#��*����+3�7C�8+��������3�� ������������

7���E��9�� (���� ���� ���� �������� �� ����� ��6� ���

����������*���������&�������������������6�

������� R�"��� �������,��S� ��� ���� ��������

R�,���S'�R�����S�#�R���� ���S��&�������������������

������������������.�����������'������������*����

��������%�'� �� �� �������� &��� ��� ��������

��������'����������*���������������.�������

�������� ������� ������� ��������� ���� ���� �����

����������� ��� �6���� �������� ����� ������ �� ��������

�-�����&�������������� �����"�����&�������������

�"������������,����.����������������������*�

�-��������%�������#������������������������������

��� �������� ������� �. +�'� �������� �� ��� .�� #�

��������� ����������� ���� �������� �� ��� ���������

5�����'� ���%�� ���� ������� &��� ��� �������� ���

�����"��������������#�����������������

!�������'� ������� ������ ���� �� ���� ����� #� ����

�������� ��� �*���� ������� ��� +3�7� ����� ������

�����������������#���������&��������������&���

�������&����������������"�������������,������

4L�.�������������������4L�.�������������������4L�.�������������������4L�.�����������������������

(� ������� ��"��'� ������� &��� ��� ��� �����*� �� ���

������������������'����������������������

������ M������ ����������� ������� &���

��������������������������������������#����(����

����������������*���������"�����.����������

&��� �������#��� ��� �������� ((.<:�� ���� ������ ���

���%�� ���"��� ������ ���� ������� �� ��"��� �� ��

����������������

�����������������������������������������������������������

C�������������������������������������������+3�7������371���

�������������35��7���E���

Actas del II congreso javaHispano

47

Page 48: Actas del II congreso javaHispano

.��� ����� ���'� ����� &��� ���� ������ ���������

�������������������&������������ ������'�#'� ���

����������#���������������������'�������� ���%�����

��������� �� ��� ��������*� �� ��� ��������� �����'�

���� ������ ��������� ����� �*������ �� ��������

"������*������������&�������������� ���������

��� ��������*� ��#� ����������� 7������

����������� ��� 3��7���E��� 8+3�79� ���� ��������

������������� M������ ��������K� ������ �������

�������������35���������������?/..�8��������������

������ ��� ������� ��� � � �� ������ ���� ��� ��� ������

������� � ��� ������������������� ��� ��� � ����� �

�������� � !"#� �� �������������������������������

$���%������

.���������������'������������������������������

�������� �� ��������� �� /)+� 0� $��-� ������� ��

�*���� �� !+3(B� � #� �� ������� �� ��� �����������

.�3�������

!�������'������������&�����������*������,����

������ ���� ���������� �������� �� ����������

������������ ��� � ��� ������ �������� ��� &��� ���

��%�����������*�����

�"������������"������������"������������"���������������

�� ����� �&������� &��� ����� ��������������� ��� &���

���� (������������ �� ���� #� <����� ���� ����

������������������������������������>��������

���� ����� ����� ������ �� ������%�� ��"6� %�� ���

"��������������

<���������<���������<���������<�����������

H4I� ������� ;�4�M��������������3��������������;�;�4�4���"�N�

H;I� ��������������� ��������F��/�����<���4G4L����%�����C'���"���;��

�����������������������������������������������������������

K�.��������������?/..�7<�?4�P4P���;/0?/� �������T��.5������

�����������2��E�"��

B�!+3(���"������!����#���� ���+����3�����#����������������������

��������������������������������������������������������-�

��������&����������������������������������*����

�����00��������������"����0�

Actas del II congreso javaHispano

48

Page 49: Actas del II congreso javaHispano

JVMTI, creación avanzada de profilers de aplicaciones con la nueva API de Tiger

Daniel Glez-Peña

[email protected] Florentino Fdez-Riverola

[email protected]

Abstract JVMTI (Java Virtual Machine Tool Interface), es la nueva API de J2SE 5.0 orientada principalmente al desarrollo de agentes de depuración y profiling.

La implementación de profilers en las versiones anteriores a J2SE 5.0, se realizaba mediante JVMPI (Java Virtual Machine Profiler Interface), todavía en fase experimental. La migración de proyectos realizados con la API antigua a la nueva, no es trivial en la mayor parte de los casos. Una diferencia importante es que JVMTI requiere casi siempre del uso de BCI (Byte-code Instrumentation), es decir, la modificación del byte-code de las clases cargadas para la generación de callbacks hacia el agente.

JavaTraceIt! es una herramienta de código libre orientada a la depuración y optimización de código Java. Su profiler había sido realizado utilizando JVMPI, por lo que ha sido necesaria su migración a JVMTI debido al fin anunciado de la antigua API.

Keywords: Java Virtual Machine Tool Interface, Java Virtual Machine Profiler Interface, Java Virtual Machine Debug Interface, JavaTraceIt!.

1 Introducción

JVMTI es una nueva interfaz nativa disponible en J2SE 5.0, que se utiliza en herramientas de desarrollo de software y de monitorización. Proporciona un modo común tanto para controlar la ejecución como para inspeccionar el estado de las aplicaciones que se ejecutan en la JVM (Java Virtual Machine). En este sentido, los dos grandes grupos de herramientas que utilizarán JVMTI son los depuradores (control de la ejecución) y los profilers (inspección del estado).

Los depuradores suelen ser parte fundamental de un IDE (Integrated Development Enviroment), siendo de gran ayuda para la detección de errores en el código. Las funciones clásicas de un depurador son la traza o ejecución paso a paso de código, el establecimiento de puntos de ruptura o breakpoints y el seguimiento de los valores de las variables. Los IDE para Java dotados de un depurador han existido desde los comienzos de la plataforma, siendo hoy en día difícil hacer un recuento de todos ellos. Ejemplos de depuradores son, por un lado, soluciones comerciales como VisualCafé, JBuilder y Sun Java Studio, y por otro, soluciones libres como NetBeans, Eclipse, BlueJ, JavaTraceIt!, etc.

Por otro lado, un profiler se puede definir como una utilidad que analiza el rendimiento de un programa con

el objetivo de encontrar posibles cuellos de botella durante su ejecución. Las funcionalidades que proporcionan son más variadas, aunque suelen ser típicas las de análisis de memoria (clases cargadas, número de instancias, bytes ocupados) y análisis de CPU (métodos invocados, su duración y su orden dentro de cada thread). Ejemplos de profilers comerciales son Borland OptimizeIt Profiler, ej-Technologies JProfiler, etc; existiendo además soluciones libres como hprof (incluido en el J2SDK), Eclipse Profiler Plugin, jprof, JavaTraceIt!, etc.

1.1 JVMPI y JVMDI

Si JVMTI es una interfaz nueva y los profilers y depuradores son herramientas ya tradicionales en Java, la respuesta a la pregunta de cómo se desarrollaban hasta ahora la encontramos en JVMPI y JVMDI, dos APIs actualmente sustituidas por JVMTI.

JVMDI (Java Virtual Machine Debug Interface) fue introducida en el J2SDK 1.1 y estaba destinada al desarrollo de depuradores. Formaba parte de JPDA (Java Platform Debugger Architecture), que sigue existiendo en J2SE 5.0, pero con la sustitución de JVMDI por JVMTI. La Figura 1 muestra de manera esquemática este hecho.

Figura 1: JPDA antes y después de J2SE 5.0.

Como se puede observar en la Figura 1, la capa superior de JPDA es JDI (Java Debug Interface), una API 100% Java de alto nivel con la que Sun recomienda que se desarrollen los depuradores. De este modo, los depuradores ya desarrollados con esta API, no se verán en absoluto afectados por la desaparición de JVMDI.

JVMPI (Java Virtual Machine Profiler Interface) fue introducida también en el J2SDK 1.1, pero siempre ha sido tratada con carácter experimental. Esta API fue migrada a la HotSpot JVM, en el J2SDK 1.3, pero nunca llegó a ser tan estable como en la JVM clásica. JVMPI presentaba múltiples inconvenientes: hacía uso de object

Actas del II congreso javaHispano

49

Page 50: Actas del II congreso javaHispano

IDs en vez de objetos JNI, lo que añadía dificultad; los formatos de volcado del montón eran complejos; ciertos recolectores de basura no funcionaban. Además, el uso de JVMPI tenía un impacto importante en el rendimiento de la JVM. Esta API ha pasado a estar obsoleta (deprecated) en el J2SE 1.5.0 (o 5.0), con vistas a ser eliminada en la próxima versión 1.6.0.

El problema se plantea en los profilers ya existentes, que usan obligatoriamente JVMPI, puesto que nunca ha existido una arquitectura mayor que pudiese abstraer a los desarrolladores de usar esta API, al contrario de lo que ocurre con JVMDI en los depuradores (ver Figura 1). La dificultad de la migración a la que están obligados los desarrolladores de profilers, dependerá del uso que se hacía de la API JVMPI, pero en la mayor parte de los casos no es un proceso sencillo, debido a los grandes cambios que se presentan en JVMTI.

A continuación se presentan los conceptos básicos de JVMTI (sección 2), los pasos básicos para la construcción de un agente JVMTI (sección 3) y una breve introducción a BCI (sección 4). Finalmente se comentan los detalles más destacables de la migración realizada en JavaTraceIt! para la adopción de JVMTI (sección 5) y se apuntan las conclusiones más relevantes.

2 Conceptos básicos de JVMTI

JVMTI puede ser vista como una interfaz de dos vías. Un cliente de JVMTI, llamado agente es notificado de sucesos de interés a través de eventos. Por otro lado, JVMTI puede controlar y consultar la aplicación a través de funciones, utilizadas en respuesta a los eventos, o de modo independiente a ellos.

Los agentes corren en el mismo proceso y se comunican directamente con la Máquina Virtual que ejecuta la aplicación monitorizada. Esta comunicación es la que se hace a través de JVMTI a través de los eventos y funciones. En general, los agentes son relativamente compactos y, en el caso de los profilers, se dedican a recolectar información durante la vida de la aplicación monitorizada. Los agentes, podrían ser controlados por un proceso a parte que implemente un front-end sin interferir en la ejecución normal de la aplicación monitorizada. La Fig. 2 muestra un esquema de la arquitectura básica de un sistema que usa JVMTI:

Figura 2: Arquitectura general de un sistema con JVMTI.

Los eventos JVMTI a los que se puede atender son muy numerosos. Dependiendo de la finalidad del agente se atenderán unos u otros. Para ello existen funciones que permiten especificar:

• Qué eventos se desean tratar. Por ejemplo, no son muy necesarios eventos orientados a un agente de depuración cuando se está realizando un agente de profiling, como pueden ser los eventos relacionados con los puntos de ruptura o breakpoints.

• Qué funcion se llamará cuando llega el evento. Es necesario establecer un puntero a una función que hará de callback para el evento.

Es preciso destacar que JVMTI no controla los eventos que llegan concurrentemente, por lo que se podría estar en dos funciones de callback a la vez, con la posibilidad de corromper las estructuras de datos que utiliza el agente. Sin embargo, JVMTI proporciona funciones para el manejo de monitores que serán muy útiles para evitar los problemas de exclusión mutua.

La Tabla 1 muestra todos los eventos de JVMTI:

Tabla1: Eventos de JVMTI.

Breakpoint Method Entry Class File Load Hook Method Exit Class Load Monitor Contended

Enter Class Prepare Monitor Contended Exit Compiled Method Load Monitor Wait Compiled Method Unload Monitor Waited Data Dump Request Native Method Bind Dynamic Code Generated Object Free Exception Single Step Exception catch Thread End Field Acess VM Death Field Modification VM Initialiation Frame Pop VM Object Allocation GC Finish VM Start

Actas del II congreso javaHispano

50

Page 51: Actas del II congreso javaHispano

GC Start

JVMTI ofrece también un número elevado de funciones, que se podrían clasificar tal y como muestra la Tabla 2.

Tabla 2: Clasificación de las funciones de JVMTI.

Manejo de Memoria

Reserva y liberación de memoria. No se deben usar funciones tipo malloc.

Threads Obtener información de los hilos y controlarlos (suspender, interrumpir, continuar, etc.). Además permite crear hilos para el agente, por ejemplo para implementar un pequeño servidor que escuche en un puerto.

Grupos de threads Obtener información de los grupos de threads

Stack Frame Obtener información de los registros de activación contenidos en la pila de cada hilo.

Montón (Heap) Recorrer el montón llegando a los objetos. Posibilidad de invocar al recolector de basura.

Variables locales Acceder a las variables locales para lectura y/o modificación.

Puntos de ruptura (Breakpoints)

Gestión de los puntos de ruptura. Orientado totalmente a depuración.

Seguimiento de variables (Watches)

Seguimiento de una variable, para detectar cuando se lee o se modifica.

Clases Información completa acerca de las clases, además de la posibilidad de modificarlas (ver sección 4).

Objetos Información básica de un objeto: hash code, tamaño y uso de su monitor.

Atributos (Fields) Información acerca de los atributos (fields) de las clases.

Métodos Información acerca de los métodos de las clases.

Monitores Manejo de monitores para evitar problemas de exclusión mutua, sobre todo en el acceso a la información que recolecta el agente.

Intercepción de funciones JNI

Mapear las funciones JNI a otras que se indiquen. Con ello se pueden capturar las llamadas a dichas funciones realizadas por código nativo de usuario.

Gestión de eventos Establecimiento de qué

eventos se quieren atender así como de qué funciones harán de callback. Además se pueden solicitar eventos pasados, que no se pudieron atender.

Capacidades (Capability)

Obtención de las posibilidades que ofrece la implementación de JVMTI de la JVM usada. Activación y desactivación de esas posibilidades para optimizar el rendimiento.

Temporizadores Utilidades para medir los tiempos de CPU usados por los distintos hilos. La temporización es muy utilizada en profiling.

System Properties Obtener información acerca de la JVM usada.

General Funciones varias.

3 Pasos para la creación de un agente JVMTI

Las posibilidades de JVMTI son mayores a las que se ven en este artículo. Sin embargo, se exponen las tareas más comunes para comenzar el desarrollo de un agente que se adapte a las necesidades de cada caso.

3.1 Inicio del agente

Lo mínimo que debe tener un agente es la función Agent_OnLoad, la cual es invocada cuando se carga la librería. En el momento en que se ejecuta esta función, la JVM no ha ejecutado todavía ningún bytecode, ni ha cargado ninguna clase, ni ha creado ningún objeto. Las tareas habituales que se realizan en esta función son:

• Especificar toda la funcionalidad que va necesitar con JVMTI. Esto se hace a través de funciones específicas que indican si la JVM que se utiliza tiene disponibles las capacidades que se precisan en su implementación propia de JVMTI. Estas funciones son las del tipo *Capabilities. Existen capacidades que pueden ser cambiadas durante la ejecución, aunque esto depende de la JVM.

• Solicitar los eventos de los que se quiere ser notificado. Para ello están las funciones relacionadas con los eventos, como por ejemplo SetNotificationMode. Además se deberá indicar un puntero a una función por cada evento, es decir, especificar las funciones de callback.

• También se suelen iniciar las estructuras de datos que vaya usar el profiler, como tablas hash que mantienen toda la información que irá recogiendo el profiler: clases cargadas, objetos creados, marcas de tiempo de entrada y salida de métodos, etc.

Actas del II congreso javaHispano

51

Page 52: Actas del II congreso javaHispano

El siguiente fragmento de código muestra una posible implementación en C++ de la función Agent_OnLoad.

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { jvmtiEnv * jvmti; jvmtiCapabilities capabilities; jvmtiEventCallbacks callbacks; /* obtener el entorno JVMTI */ vm->GetEnv( (void **)&jvmti, JVMTI_VERSION); /* exigir capacidades */ jvmti->GetCapabilities( &capabilities); capabilities.can_generate_all_class_hook_events = 1; jvmti->AddCapabilities( &capabilities); /* Establecer los punteros a las funciones callback vmInit y classFileLoadHook son dos funciones que se han definido previamente. */ memset(&callbacks, 0, sizeof(callbacks)); callbacks.VMInit = &vmInit; callbacks.ClassFileLoadHook= &classFileLoadHook; jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); /* Activar los eventos que queremos */ jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); return JNI_OK; }

3.2 Atendiendo a un evento

Una vez inicializado, el trabajo del agente consistirá en atender a los eventos que le lleguen, actualizando sus datos y utilizando funciones, bien cuando llega un evento o bien en otro momento, por ejemplo cuando se le solicita desde otro proceso que coopera con él.

El siguiente ejemplo muestra un fragmento de código para atender al evento VM Object Alloc, que es enviado cuando la JVM crea un objeto que no es de usuario. Para los objetos de usuario se debe usar BCI, comentado en la sección 4.

/* Función de callback para los eventos VM Object Allocation */ static void JNICALL callbackVMObjectAlloc(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jobject object, jclass object_klass, jlong size) { ... char *className; ... if (size > 50) { jvmti->GetClassSignature(jvmti, object_klass, &className, NULL); if (className != NULL) { printf("\nSe ha creado un objeto de la clase %s que ocupa %d\n", className, (jint)size);

} ...

3.3 Compilación y ejecución del agente

Para compilar el agente JVMTI se deben ejecutar los siguientes pasos:

Considerando que el J2SE está en el directorio /jdk1.5.0 y que la plataforma es Linux, nos situaremos en el directorio de donde estén los ficheros fuente y ejecutaremos:

>g++ –c –I/jdk1.5.0/incluye –I/jdk1.5.0/include/linux *.c >g++ –shared –o libagent.so *.o

El agente quedará compilado en libagent.so. Para ejecutar una aplicación Java que utilice el agente se deberán ejecutar los siguientes comandos (se considera que libagent.so está colocado en el mismo directorio que la aplicación Java):

>LD_LIBRARY_PATH=. >java –cp . –agentlib:agent Aplicacion

4 BCI: Bytecode Instrumentation

JVMTI no incluye muchos eventos que podrían considerarse imprescindibles. Ejemplo de ello son los eventos de creación de un nuevo objeto de usuario, o eventos eficientes de entrada y salida de métodos. Sin embargo, JVMTI proporciona el soporte para BCI (Bytecode Instrumentation), es decir, la posibilidad de alterar el bytecode del programa objetivo de optimización. Antes de explicar cómo se puede utilizar esta técnica en JVMTI, se hará una breve introducción a la misma, cuyo uso es cada día más frecuente.

Se pude definir BCI como la técnica destinada a la modificación directa de Bytecode Java. La mayor parte de las aplicaciones que usan BCI son herramientas de monitorización, profiling y de AOP (Aspect Oriented Programming). La intención es poder inyectar instrucciones en el código objeto (.class) del usuario en lugares estratégicos o puntos significativos, como por ejemplo la entrada o salida de un método, para realizar acciones generalmente de aviso.

La Figura 3 muestra cómo se modifica el código de usuario a la entrada y salida de un método para notificar a rutinas de análisis.

Actas del II congreso javaHispano

52

Page 53: Actas del II congreso javaHispano

Figura 3: Uso de BCI para detectar llamadas a métodos.

Un ejemplo muy ilustrativo se tiene en AOP que, en líneas muy generales, consiste en interceptar el código de usuario en lugares concretos (join-points), para ejecutar el código arbitrario que implementa el aspecto (advice). Esto se consigue añadiendo el código necesario en la zona de usuario, que provoque una llamada al código que implementa el aspecto. De esta tarea se encarga en general el compilador de AOP.

Existen numerosos productos que usan esta técnica. Por ejemplo, software orientado a la monitorización de sistemas como Wily Technology – Introscope, HP OpenView Transaction Analyzer, la mayor parte de los profilers como OptimizeIt, JProfiler, JProbe y herramientas AOP como AspectJ y AspectWerkz.

Para desarrollar una aplicación que necesite usar BCI, existen también librerías, muchas de libre distribución, como por ejemplo BCEL (Apache Bytecode Engineering Library), BIT (University of Colorado – Bytecode Instrumenting Tool), ej-Technologies – jclasslib, etc. Todas ellas son librerías Java que permiten la manipulación de ficheros .class y su transformación.

Además de las librerías anteriores, se dispone de java_crw_demo (Java Class Read-Write Demo), incluida en J2SE 5.0 como una librería dinámica (.dll o .so). La aparición de JVMTI viene, por tanto, acompañada de esta librería. De hecho, el conocido profiler hprof que se distribuye con el J2SDK, hace uso de ella ya que fue migrado de JVMPI a JVMTI. java_crw_demo ofrece funciones básicas para la manipulación de bytecode, suficiente en muchos casos para la mayoría de las implementaciones. De ella se hablará en el siguiente apartado.

4.1 BCI en JVMTI

Las alteraciones más comunes que se hacen en el bytecode de usuario con BCI son la inclusión de “eventos” al código de un método, como por ejemplo, el añadir al comienzo de un método la llamada a MiProfiler.metodoLlamado(). Debido a que estos cambios

son puramente adiciones, no modifican el estado o comportamiento de la aplicación. El hecho de que la inserción se haga en estándar bytecode, implica que la JVM puede ejecutarse rápidamente. El resultado es que se habrán generado eventos muy eficientes. Esta aproximación proporciona además un control total por parte del agente, ya que la inserción de código podría restringirse a porciones muy concretas del programa (por ejemplo, sólo código de usuario, no de librerías estándar o de sistema). Una vez que se produzca el evento, se puede tratar en código Java o redirigir el evento hacia el agente nativo.

La Figura 4 muestra un ejemplo de inserción de bytecode en código de usuario para ser tratado después por el agente.

Figura 4: Inserción de bytecode en una clase de usuario.

La manipulación de bytecode puede ser llevada a cabo en tres momentos distintos:

• Estáticamente: se trata de modificar los ficheros .class antes del momento de la ejecución, como se suele hacer en AOP. Esta opción no es muy útil JVMTI.

• En el momento de carga. La modificación se produce justo antes de la carga de la clase. Para ello JVMTI proporciona el evento ClassFileLoadHook, que avisa cada vez que una clase está a punto de cargarse, proporcionando la oportunidad de modificarla. Esto ya existía en JVMPI.

• Dinámicamente. La modificación de la clase se realiza una vez cargada la clase, en cualquier momento posterior, incluso habiendo sido ejecutada ya. Para ello, JVMTI proporciona la función RedefineClasses. Esta funcionalidad no existía en JVMPI.

El evento ClassFileLoadHook y la función RedefineClasses es todo lo que proporciona JVMTI para realizar BCI. Es decir, da la oportunidad de realizar modificaciones, pero no realiza la modificación en sí, es responsabilidad del programador del agente JVMTI trabajar a nivel de bytecode con cada clase. Es por ello por lo existe la librería dinámica java_crw_demo mencionada anteriormente, que permite realizar unas modificaciones básicas sobre el código de una clase.

Actas del II congreso javaHispano

53

Page 54: Actas del II congreso javaHispano

Las inserciones de bytecode que java_crw_demo realiza en una clase provocan una llamada hacia una clase y método que se le indique. Estas inserciones se pueden hacer hasta en cuatro lugares distintos:

• En el constructor de java.lang.Object: con ello se puede capturar la creación de cualquier objeto, ya que todos pasan obligatoriamente por este método. Es decir, se habrá recuperado un evento disponible en la antigua JVMPI, que ahora no hay: JVMPI_EVENT_OBJECT_ALLOC.

• A la entrada de todos los métodos de la clase indicada.

• A la salida de todos los métodos de la clase indicada.

• Inmediatamente antes de cualquier creación de un array. Con ello se puede capturar el momento de la creación de un objeto array.

5 Migrando JVMPI a JVMTI. Un ejemplo práctico: JavaTraceIt!

En esta sección se muestra un ejemplo real de la migración de un profiler de JVMPI a JVMTI.

JavaTraceIt! implementa un depurador y optimizador de código libre para Java. Fue presentado en el I Congreso JavaHispano de 2003.

JavaTraceIt! consta de dos partes bien diferenciadas. Por un lado implementa un depurador que permite realizar la ejecución paso a paso del código, el establecimiento de puntos de ruptura y la inspección/modificación de las variables en memoria. El depurador ha sido desarrollado con JPDA (ver apartado 1.1). Por otro lado, implementa un profiler con un analizador de memoria que permite visualizar las clases cargadas, el número de instancias de cada clase y los bytes ocupados por los objetos de cada clase.

La Figura 5 muestra una captura de JavaTraceIt! y de su profiler en ejecución.

Figura 5: El profiler de JavaTraceIt!.

El profiler de JavaTraceIt! había sido desarrollado inicialmente con JVMPI, la única alternativa disponible cuando se implementó. La desaparición anunciada de JVMPI a favor de JVMTI ha motivado la migración del profiler a la nueva interfaz. A continuación se explican los pasos más relevantes en el trabajo realizado.

La arquitectura del sistema de profiling de JavaTraceIt! es muy similar a la que se muestra en la Figura 2. JavaTraceIt! presenta un front-end como se puede apreciar en la Figura 5. En el antiguo sistema de profiling, había un agente JVMPI que corría en el mismo proceso que la JVM de la aplicación monitorizada. Su trabajo se dividía en dos partes:

• Capturar los eventos necesarios para elaborar las tablas donde se guardaban las clases cargadas, número de instancias y bytes ocupados.

• Atender las peticiones desde el front-end a través de un protocolo propio. Estas peticiones podían ser la solicitud de las tablas para

Actas del II congreso javaHispano

54

Page 55: Actas del II congreso javaHispano

mostrarlas gráficamente y la ejecución del recolector de basura. Para ello, el agente implementaba un pequeño servidor a través de sockets por el que se recibían las órdenes y se devolvían los datos de las tablas.

Debido a la existencia de un protocolo propio que separaba el front-end del agente, no ha sido necesario tocar el front-end, simplemente se exige que el nuevo agente JVMTI implemente el mismo protocolo.

La migración del servidor ha sido muy sencilla. Lo único que se requería era la capacidad de JVMPI de proporcionar un hilo nuevo para que se pudiese ejecutar atendiendo peticiones. JVMTI tiene también esa capacidad con la función RunAgentThread.

El trabajo con los eventos no ha sido tan sencillo como el caso anterior. Los eventos más importantes que atendía el agente con JVMPI eran los siguientes:

• JVMPI_EVENT_CLASS_LOAD (carga de una clase). Cuando se cargaba una clase se creaba una nueva posición para ella en las tablas hash.

• JVMPI_EVENT_OBJECT_ALLOC (creación de un objeto). Cuando se creaba un objeto se consultaba de qué clase era y se incrementaba en uno el número de instancias de esa clase.

• JVMPI_EVENT_OBJECT_FREE (eliminación de un objeto). Cuando se eliminaba el objeto se averiguaba si estaba guardado, ya que uno de los problemas de JVMPI es que no avisaba de todas las creaciones de objetos, por lo que podía avisar de la liberación de objetos de los cuales no había sido informada su creación. Si no se tenía registrado, no se hacía nada, en caso contrario se restaba uno al número de instancias de su clase.

La migración de JVMPI_EVENT_CLASS_LOAD no ha supuesto ningún problema ya que existe su equivalente en JVMTI.

El problema más importante lo presenta sobre todo el evento de JVMPI_EVENT_OBJECT_ALLOC que, como se ha mencionado en la sección 4, no existe equivalente en JVMTI. Para conseguir de nuevo ese evento ha sido necesario incluir BCI, es decir, modificar el Bytecode de las clases. Para ello se utiliza la librería java_crw_demo como se explica en el apartado 4.1.

La idea consiste en modificar la clase java.lang.Object incluyendo al comienzo del constructor una llamada a un método estático de una clase propia: Tracker.ObjectInit(). Por lo tanto, cada objeto creado invocará al construirse a este método. Esta idea es la misma que sigue el profiler hprof cuyo código fuente está disponible. El código de la clase Object se realiza justo cuando se carga. Se utiliza por tanto el evento ClassFileLoadHook, que es el mecanismo que ofrece JVMTI para poder realizar BCI. Una vez que la función Tracker.ObjectInit() se invoca, se transfiere el control a través de JNI al agente.

Para la captura de la creación de arrays, también se inyecta código en todos los métodos de las clases cargadas donde se crea un array. Dicho código introduce una llamada a Tracker.NewArray().

El siguiente fragmento de código corresponde a la clase Tracker:

public class Tracker { /* Para contar el numero de instancias se necesita capturar la creacion de objetos y de arrays.*/ /* Al principio de java.jang.Object.<init>(), se inyecta una llamada a Tracker.ObjectInit().*/ private static native void nativeObjectInit(Object thr, Object obj); public static void ObjectInit(Object obj) { … nativeObjectInit(Thread.currentThread(), obj); … } /* Inmediatamente despues del bytecode newarray, se inyecta una llamada a Tracker.NewArray(). */ private static native void nativeNewArray(Object thr, Object obj); public static void NewArray(Object obj) { … nativeNewArray(Thread.currentThread(), obj); … }

Como se puede observar en el fragmento de código anterior, existen métodos nativos a los cuales se invoca desde las funciones ObjectInit y NewArray. Estos métodos están también implementados y registrados en el agente, es decir, cuando se llaman el control lo toma el agente para que pueda actualizar sus tablas.

Por último, el evento JVMPI_EVENT_OBJECT_FREE, proporciona uno similar en JVMTI. La diferencia que existe es que en JVMTI el evento no llega para todos los objetos, sino que solamente para aquellos objetos “marcados” (tagged). JVMTI permite establecer una marca a cualquier objeto (un jlong) a través una función. Con esto se evita que llegue este evento sobre un objeto del que el agente no tiene información de su existencia, problema que presentaba JVMPI.

6 Conclusiones

En la actualidad la demanda de profilers Java está en aumento. La enorme carga transaccional que pueden llegar a tener las aplicaciones J2EE puede generar problemas en producción. Es por ello que las herramientas de monitorización, como son los profilers, pueden ser de gran ayuda en esas situaciones. Con JVMTI, la plataforma Java ya dispone de una interfaz estándar para desarrollar este tipo de aplicaciones, que

Actas del II congreso javaHispano

55

Page 56: Actas del II congreso javaHispano

permitirá a los desarrolladores no sólo comerciales el poder crear sus propias utilidades para la monitorización y optimización de las aplicaciones Java, de un modo sencillo y eficiente.

La transformación que ha sufrido la antigua API JVMPI hacia JVMTI ha traído consigo ventajas ya mencionadas en el presente trabajo, aunque obligue al uso de BCI en la mayor parte de los casos. Sin embargo esta evolución está justificada ya que esta técnica permite la creación de profilers muy eficientes, restricción básica en este tipo de herramientas.

Referencias

[1] Sun Microsystems. JVM Tool Interface v.1.0. http://java.sun.com/j2se/1.5.0/docs/guide/jvmti/jvmti.html.

[2] Sun Microsystems. The Java Virtual Machine Profiler Interface (JVMPI). http://java.sun.com/j2se/1.4.2/docs/guide/jvmpi/jvmpi.html

[3] C.K. Prasad, Rajesh Ramchandani, Gopinath Rao, y Kim Levesque. Creating a Debugging and Profiling Agent with JVMTI. http://java.sun.com/developer/technicalArticles/Programming/jvmti/

[4] Kelly O’Hair. The JVMPI Transition to JVMTI. http://java.sun.com/developer/technicalArticles/Programming/jvmpitransition/

[5] Sun Microsystems. Java Platform Debugger Architecture (JPDA). http://java.sun.com/products/jpda/index.jsp.

[6] Joseph Coha y David Seidman. Bytecode Instrumentation – Making it simple. JavaOne 2004. http://www.hp.com/products1/unix/java/pdfs/bytecode.pdf

[7] Han Bok Lee. BIT: Bytecode instrumenting tool. University of Washington, 1996. http://www-plan.cs.colorado.edu/hanlee/pubs/master.pdf

[8] Apache Software Foundation. BCEL: Bytecode Engineering Library. http://jakarta.apache.org/bcel/index.html.

[9] Ej-Technologies - jclasslib. http://www.ej-technologies.com/products/jclasslib/overview.html

[10] D. Glez-Peña, F. Fdez-Riverola. JavaTraceIt: Depurador y optimizador de aplicaciones Java. I Congreso javaHispano, Madrid, España, Octubre 2003. http://congreso.javahispano.org/files/doc/j2se/JavaTraceIt_depurador_y_optimizador.pdf

Actas del II congreso javaHispano

56

Page 57: Actas del II congreso javaHispano

JNIEasy, Aspect Oriented Programming a la ayuda de Java como ciudadano de primera clase en el desktop

Jose María Arranz Santamaría [email protected]

[email protected]

Abstract

Las necesidades en el desktop son habitualmente mucho

más complejas y diversas que en el servidor, las

aplicaciones normalmente necesitan acceder directamente a

recursos hardware o servicios del sistema operativo no

necesariamente cubiertos por el Java estándar, con los que

se consigue una mayor integración con el sistema y una

mayor familiaridad para el usuario. Este problema ha sido

resuelto por Java programando con lenguajes nativos

(C/C++) usando el complejo JNI y necesitando un

compilador o un IDE. La realidad muestra que buena parte

de los desarrolladores de Java no conocen C/C++.

JNIEasy[1] es una herramienta que permite la interacción

con librerías nativas (DLLs) para acceder directamente

desde Java a recursos del S.O. o a hardware especializado

sin necesidad de programar con JNI, C o C++. Los

programas desarrollados con JNIEasy serán 100% Java,

pudiendo llamar desde Java a métodos nativos contenidos

en DLLs, exponer automáticamente métodos de clases

normales a llamadas desde código nativo (callbacks), definir

“estructuras nativas” como simples clases, y gestionar la

“memoria nativa” de forma automática con el garbage

collector. Las soluciones existentes hasta ahora no han

conseguido una solución tan transparente y céntrica en

Java, gracias a la Aspect Oriented Programming y el

bytecode enhancement.

Keywords: Java, JNI, AOP, bytecode enhancement, C, C++, DLL, transparencia

1 El dominio casi absoluto de las tecnologías Windows en el desktop

De todos es sabido la enorme penetración que tiene Java

en el mundo del software, Java es sin duda una de las

tres plataformas relevantes de desarrollo software

actualmente junto con .Net y LAMP

(Linux+Apache+MySQL+Perl/PHP).

Pero no nos engañemos, Java al igual que la plataforma

LAMP tiene su relevancia fundamentalmente en

aplicaciones basadas en Web y especialmente en gestión

de bases de datos. Este papel muy relevante en el Web

se debe a varios factores entre otros:

1) La portabilidad de Java entre sistemas

En un mundo, el del servidor, en donde Linux y otras

plataformas Unix han tenido un gran papel al ofrecer

tradicionalmente potencia y robustez. Y siguen

teniéndolo gracias en parte a Java y a la explosión de

servicios y comercio electrónico basados en Web que nos

trajo la burbuja tecnológica. El papel de JDBC ha sido

fundamental permitiendo una conectividad con bases de

datos más estandarizada y portable que las soluciones

basadas en ODBC, y OleDB.

2) La portabilidad de las tecnologías Web y la casi

independencia tecnológica entre el cliente y el

servidor

Por ejemplo, nada impide que Java en un servidor no

Windows produzca HTML transmitido por HTTP

consumido en Windows por el Internet Explorer.

3) La calidad, fiabilidad, seguridad, robustez y

capacidad de gestión de la complejidad que ofrecía

Java como plataforma frente a soluciones más

“amateur” como ASP o PHP, o frente a la

inseguridad y complejidad que ofrece C/C++ poco

apto para el mundo esencialmente “concurrente”

que exige el Web.

4) La “familiaridad” de Java con las tecnologías

subyacentes a Internet (http, applets, RMI etc)

5) La aparición de una pléyade de frameworks

orientados fundamentalmente a simplificar el

desarrollo Web y la manipulación de bases de datos,

desde los estandarizados (J2EE=JSP+EJB, JSF, JDO)

con versiones libres y comerciales, hasta los

Actas del II congreso javaHispano

57

Page 58: Actas del II congreso javaHispano

populares de código abierto como Struts, Hibernate,

Spring etc.

Sin embargo todo cambia cuando lo vemos desde el

punto de vista de los sistemas orientados a ser usados

como puesto de trabajo individual es decir el llamado

desktop o escritorio.

Varios hechos:

1) Windows está instalado en más del 90% de los

computadores del mundo [2]

2) La gran mayoría de aplicaciones Windows

orientadas al desktop están desarrolladas con

tecnologías Microsoft (Visual C++, Visual Basic)

sean aplicaciones de Microsoft o no.

3) Windows está fuertemente componentizado,

normalmente a través de dichos componentes

accedemos a los recursos del hardware o a los

servicios del sistema operativo.

4) La API primaria con la que Windows se “expone” es

C (Platform SDK), las demás son capas sobre ésta

(incluido el COM). El SDK C es gratuito.

5) Los drivers propietarios que acceden a los recursos

del hardware exponen prácticamente siempre una

interfaz C o COM.

Java ha hecho un gran esfuerzo por ofrecer una “capa”

Java para cualquier necesidad permitiendo una

integración portable con el S.O., pero la experiencia dice

que no siempre es posible “esperar” que Sun (o en

general el ecosistema Java) lo haga, pues obviamente

Microsoft siempre irá delante en sus propias tecnologías.

Esfuerzos como el JDIC[3] o el JMF[4] son encomiables,

pero en el caso del JMF, un componente tan básico,

todavía no tiene lugar en el JRE y su licencia es todavía

demasiado restrictiva.

De todas formas existen infinidad de casos no típicos,

normalmente acceso a hardware propietario, en donde

es difícil esperar una solución estándar, ni siquiera del

propio fabricante, el “háztelo tu mismo si puedes” es la

regla.

2 WORA, realidad y utopía

El WORA (Write Once Run Anywhere) es la utopía

deseada por Sun (y competidores en el mismo “lado”)

para poder vender más hardware y arrebatar un trozo

de pastel al mundo Microsoft/Intel (aunque ahora el reto

también está contra Linux/Intel).

El WORA es un hecho en el lado del servidor, pero está

todavía lejos de conseguirse en el desktop. El terreno del

desktop está lleno de “piedrecitas” en donde una

solución relativamente sencilla en C, C++, Visual Basic ¡y

ahora en .Net!, puede ser un verdadero “pain in the ass”

en Java, cuando ha de accederse directamente al sistema

operativo o al hardware, y no siempre estamos hablando

de necesidades de alto rendimiento que justifiquen JNI.

En este sentido Java está hoy día en una encrucijada: o

conquista un aceptable territorio en el desktop o puede

perder definitivamente esa batalla (como la perdió

Borland con C++ y Delphi), en la medida en que .Net es

un competidor directo de Java, obviamente se integra

muy bien con Windows, no es un juguete para amateurs

como en cierto modo era Visual Basic, ni tan complejo e

inseguro como era el Visual C++.

En esta guerra hay muchos factores, ciertamente se

necesita mucho más WORA pero quizás también una

visión más pragmática y menos exigente a corto plazo:

más “Java for Windows only”, huyendo de la “palabra

maldita” que hace inclinar la balanza por el universo

Microsoft: JNI

3 JNI amigo y enemigo

La programación en lenguajes nativos es más compleja

que con Java y menos robusta, JNI es relativamente

complejo como mezcla de dos mundos (Java y nativo)

pues supone programar “en Java” pero con C/C++.

Cuando se realiza una aplicación Java con JNI siempre

existe la lucha entre si más Java o más C/C++, el

modelar dos veces, la conversión de datos etc. De hecho

no es raro que el resultado sea una aplicación basada en

código nativo fundamentalmente y una fina capa Java.

El problema no es el JNI en sí mismo, JNI tiene el

importantísimo papel de no permitir que Java sea una

plataforma cerrada. En algunas aplicaciones en donde se

necesita una comunicación íntima con el hardware con

alto rendimiento es insustituible, pero es sin duda una

de las grandes piedras que se encuentra Java en el

desktop: cuando es la única alternativa para problemas

que no resuelve Java (es decir, que otros todavía no han

resuelto con JNI).

Ejemplo ilustrativo: Sourceforge.net, el inmenso

repositorio de aplicaciones de código abierto, Java goza

Actas del II congreso javaHispano

58

Page 59: Actas del II congreso javaHispano

de muy buena salud (ver Tabla 1, muchos de los

proyectos es sabido que combinan C y C++ y el propio

Java por lo que no son “sumables”).

Tabla 1: Lenguajes en Sourceforge

Lenguaje Proyectos Java 13274

C 13807 C++ 14117

Visual Basic 1977

C# 1976

Sin embargo filtremos la categoría: Multimedia / Vídeo y

con combinaciones de lenguajes entre Java, C y C++

(Fig. 1).

Figura 1: Sourceforge, lenguajes en proyectos de vídeo

(noviembre de 2004)

Tabla 2

Lenguaje Proyectos Java sin C o C++ 10

Java con C o C++ 13

C o C++ sin Java 87

De acuerdo con la Tabla 2 podemos concluir que Java no

es muy relevante en áreas como la manipulación de

vídeo, tarea típica de desktop, y lo normal es que venga

acompañado de programación en lenguajes nativos (JNI

con gran probabilidad).

4 Aspect Oriented Programming y el bytecode enhancement

Aunque no son filosofías y tecnologías nuevas, es en este

momento cuando están teniendo un gran auge, en

concreto la AOP, pero hablar de AOP en Java casi no es

posible sin el bytecode enhancement, los dos

frameworks más relevantes: AspectWerkz y AspectJ

están basados en esta técnica (existen otras como los

proxies dinámicos, usados en Spring, pero el alcance de

posibilidades es menor), ambos vienen a ser la expresión

formal y bien estructurada de los conceptos de la AOP, y

de las posibilidades que permite el bytecode

enhancement.

El bytecode enhancement es AOP en su sentido más

primitivo, consiste en la introducción de código nuevo

Java, precompilado, directamente en las clases a nivel de

bytecode, así como la modificación de código ya

existente. A través de esta técnica se consigue el objetivo

de la AOP de resolver de forma elegante (ortogonal) los

llamados crosscutting concerns, en síntesis, tareas o

problemas que no pueden expresarse de forma directa a

través de una clase base o derivada o por agregación, y

que su resolución por las técnicas habituales supone la

diseminación de pedazos de código similares por

multitud de puntos del programa de forma fuertemente

intrusiva.

A través de bytecode enhancement podemos acometer

en síntesis los objetivos de la AOP:

1) Añadir nuevos métodos y atributos a una clase

preexistente

2) Introducir llamadas a los nuevos métodos

(advices) en ciertos puntos del código original

(pointcuts) dentro del conjunto de puntos de

unión posibles (joinpoints)

El conjunto de nuevas funciones (advices), atributos y

poincuts orientados a realizar una cierta tarea es lo que

se denomina en AOP aspecto.

En JNIEasy no se utiliza ningún framework AOP concreto,

sino que se utiliza directamente bytecode enhancement,

la razón hay que buscarla en la gran libertad de

manipulación que permite respecto a usar un framework

concreto, pues todo framework al mismo tiempo que

supone una formalización elegante de un servicio,

supone al mismo tiempo la introducción de limitaciones,

la analogía hay que encontrarla por ejemplo entre

programar en C o en ensamblador. De todas formas no

está descartado introducir en el futuro un framework,

seguramente AspectWerkz, más flexible que AspectJ.

La razón de usar bytecode enhancement es una absoluta

necesidad, sin el mismo no sería posible conseguir el

nivel de transparencia que ofrece JNIEasy, la alternativa

es usar las técnicas claramente intrusivas “y poco Java”

que han acompañado hasta ahora las aproximaciones

clásicas al problema.

Actas del II congreso javaHispano

59

Page 60: Actas del II congreso javaHispano

5 JNIEasy hacia una solución Java sin JNI

5.1 Estrategias de diseño

La finalidad de JNIEasy es muy simple: sustituir a JNI, es

decir, ser un nuevo Java Native Interface pero basado

totalmente en Java desde el punto de vista del

programador. De esta manera conseguimos eliminar la

problemática mezcla de C/C++ y Java.

Hay dos aproximaciones o estrategias al problema:

1) Crear un modelo Java que represente los tipos de

datos, las instancias y la forma de manipular la

memoria de un programa en C

2) Vincular la forma “normal” de manipulación y tipos

de datos de Java a la manipulación nativa

JNIEasy utiliza la segunda estrategia y el resultado es una

mayor transparencia y familiaridad.

Analicemos la primera opción con varios ejemplos

tomados de otro producto con similar objetivo [5]:

Int value = new Int(); // int Pointer pValue=new Pointer(value); // int* En este ejemplo se hace una correspondencia directa

entre el tipo de datos nativo C int con un objeto Java,

la instanciación de un objeto Int vendría a ser como la

declaración C de una variable (int value; por

ejemplo). A continuación se crea un objeto Pointer que

albergará la dirección de memoria que apunta al dato

entero value. Como vemos se identifica un objeto Java

por cada dato nativo correspondiente que se quiere

poner en memoria.

Veamos una llamada a función:

// int sprintf(const char*,…); C Function sprintf = new Library("msvcrt") .getFunction("sprintf"); AnsiString result = new AnsiString(); sprintf.invoke(null,result, new AnsiString("Hello, %s!"), new AnsiString("World")); System.out.println(result.getValue()); //Output: Hello, World! Como se puede observar las cadenas que se pasan como

parámetros se envuelven en objetos especiales

AnsiString y el retorno también cadena es pasado

como parámetro.

Sea la definición de una estructura:

// C: struct TestStruct { short a; int b;}; private static class TestStruct

extends Structure { public Int16 a = new Int16(); public Int32 b = new Int32(); public TestStruct() { init(new Parameter[] {_int16,_int32});} } Aparte de lo intrusivo que supone la necesidad de

derivar de la clase Structure, tampoco nos ofrece una

natural simetría ni con una clase Java con dos atributos

short e int ni con la propia estructura C original.

Veamos la definición de una callback: una callback en C

es una función diseñada para ser llamada normalmente

desde dentro de otra función en donde la dirección de

memoria de la callback ha sido dada como argumento:

/* C callback: int callback(int); */ private static class IncIntCallback

extends Callback { private Int _arg = new Int(); private Int _result = new Int(); public IncIntCallback() { init(new Parameter[] {_arg},_result);} public void callback() { _result.setValue(_arg.getValue()+1);} } Como se puede comprobar los parámetros “formales” de

la función están expresados como atributos de la

callback, expresada como una clase Java. Dichos

atributos recibirán los valores de la llamada cuando se

produzca y el resultado se pondrá en un atributo

específico.

La consecuencia de éste enfoque es código Java que no

parece Java” ni siquiera programación C.

El desarrollo de JNIEasy tuvo en cuenta este problema

desde el principio, de ahí que uno de los principales

principios rectores fuera no tanto expresar en Java el

modelo nativo C sino más bien lo contrario corresponder

el modelo de trabajo normal de Java con el modelo

nativo. Para ello JNIEasy emplea un arsenal de técnicas

desde la AOP via bytecode enhancement, código C y

C++ con JNI, ensamblador e incluso generación

dinámica de código máquina.

Punto de vista de JNIEasy:

String cadena = new String("Texto");

Actas del II congreso javaHispano

60

Page 61: Actas del II congreso javaHispano

Representa en JNIEasy desde el punto de vista nativo a

una cadena de caracteres (char) acabada en un nulo

('\0') instanciada en memoria a la que apunta un

puntero (de tipo const char*) que equivale a la

referencia String cadena en Java. Aunque el objetivo

no se consigue 100% el alcance conseguido es

probablemente el más alto de las herramientas

disponibles.

Lo demostraremos a continuación con ejemplos que nos

servirán para descubrir la “naturalidad” de uso y las

capacidades de JNIEasy.

5.2 Llamadas a funciones

Consideremos la siguiente función de la API Win32:

HWND FindWindow( LPCTSTR lpClassName, // class name LPCTSTR lpWindowName ); // window name Su finalidad es devolver el handler de la ventana cuya

clase y nombre (título) vienen dados por dos cadenas, la

clase es opcional y puede ser NULL.

JNIEasy necesita conocer cómo es dicha función para

poder convertir la llamada Java en llamada nativa:

JNIEasy.getInstance().load(); DynamicLibrary user32DLL = JNIEasy.getInstance().getDLLManager().get(

"User32.dll"); CMethod method = user32DLL.addCMethod("FindWindowA", int.class, // tipo de retorno new Class[] { String.class, // nombre clase String.class }, // nombre ventana CallConv.STD_CALL ); // method representa al método C en la DLL int hwnd = method.callInt(new Object[] {null, "DDE Server Window"} ); Notar que utilizamos directamente un objeto String

como argumento al igual que el null análogo al NULL

en C (y no un Pointer() cuyo contenido sea un nulo

según la anterior estrategia). El dato devuelto es un int

lo que nos simplifica la programación y evita la

necesidad de objetos especiales, de hecho cuando es

necesario manejar int como objeto (como argumento

por ejemplo) JNIEasy usa el tipo básico Integer (lo

mismo puede decirse para los demás tipos básicos long,

byte, char etc), por eso es también válido llamar como:

Integer hwndObj = (Integer)method.call(new Object[] {null,"DDE Server Window"} ); En donde el método “call” es agnóstico en el tipo de

retorno (debe ser Object).

Sólo es necesario obtener una sola vez el objeto que

representa el método, a cambio en todas las llamadas los

parámetros son supervisados comprobando que sean del

tipo adecuado, lo cual da una robustez mayor que la que

ofrece la misma llamada en lenguaje nativo.

Es recomendable y más cómodo poner todas las

funciones de una DLL en una clase al efecto:

public class User32 { public static DynamicLibrary dll

= JNIEasy.getInstance(). getDLLManager().get("User32.dll"); public static GenericMethod[] methodList = new GenericMethod[…]; static { methodList[0] = dll.addCMethod("FindWindowA",... ); ... } public static int findWindow(String className,String windowName) { CMethod method = (CMethod)methodList[0]; return method.callInt(new Object[]

{ className, windowName} ); } . . . Conscientes de que esta es una tarea tediosa, JNIEasy

dispone de un generador de código Java a partir de una

sucinta descripción de los métodos en XML. Ejemplo de

fragmento de declaración en XML:

<method returnType="int" name="findWindow" nativeName="FindWindowA" type="C" conv="STD_CALL" > <param type="String" name="className" /> <param type="String" name="windowName" /> </method>

5.3 Polimorfismo en funciones

Cualquier programador en C conoce que aunque no es

válido el polimorfismo de funciones en C, el lenguaje es

lo suficientemente débil en su tipado para permitir un

cierto grado de polimorfismo.

Actas del II congreso javaHispano

61

Page 62: Actas del II congreso javaHispano

Por ejemplo, en el caso de un puntero a cadena de

caracteres, const char*, aunque nuestra

correspondencia “natural” en Java es un objeto String

o StringBuffer, la cabecera de la función C admite

realmente como parámetro un entero, la dirección de

memoria de la cadena.

JNIEasy evita la simplificación de identificar nombre de

función nativa – función Java , usando la más compleja

idea de “signatura” de función tal y como se emplea en

C++ o Java para el polimorfismo de funciones: dos

funciones son diferentes si cambia el nombre o el tipo de

alguno de los parámetros.

Por tanto sería válido añadir un nuevo método:

CMethod method = user32DLL.addCMethod( "FindWindowA",int.class, new Class[] { int.class, // nombre clase int.class }, // nombre ventana CallConv.STD_CALL ); Pudiendo usar enteros (direcciones de memoria) para

indicar las cadenas.

Igualmente es posible obtener referencias a los métodos

registrados con el mismo nombre:

List methods = user32DLL.findMethods("FindWindowA"); u obtener el método exacto indicando la signatura a

través de un objeto Signature :

CMethodSignature sig = SignatureUtil.newCMethodSignature(int.class ,new Class[]{String.class,String.class}); method = user32DLL.findCMethod(

"FindWindowA", sig);

5.4 Unicode

El uso del Unicode está cada vez más generalizado y

soportado por las herramientas software: los lenguajes

modernos como Java lo soportan nativamente, C y C++

incorporan caracteres Unicode (wchar_t de 16 bits) y la

API Win32 tiene todas las funciones que usan cadenas

con dos prototipos: ANSI (terminadas en A) y Unicode

(terminadas en W).

JNIEasy es por defecto ANSI pero puede usarse Unicode

como codificación por defecto o explícita.

Voluntariamente podemos indicar que un parámetro (o

retorno) es ANSI o Unicode cambiando el tipo de datos

del parámetro (o retorno). Para ello se dispone de las

interfases StringAnsi y StringUnicode:

CMethod method = jniEasyDLL.addCMethod( "FindWindowW",int.class, new Class[] { StringUnicode.class, // class name StringUnicode.class }, // window name CallConv.STD_CALL); int hwnd = method.callInt(new Object[] {null, "DDE Server Window"} ); Aunque este método “espera” objetos StringUnicode

como parámetros, JNIEasy sabe que los objetos String

son compatibles, el resultado será una llamada a la

versión Unicode de FindWindow usando cadenas en

Unicode.

5.5 Callbacks

Es posible programar callbacks en Java, funciones en

Java que serán llamadas directamente desde código

nativo como si fueran funciones nativas.

Veamos un ejemplo: Win32 dispone de una función

EnumWindows que enumera a través de una callback

todas las ventanas presentes en el desktop.

BOOL EnumWindows( WNDENUMPROC lpEnumFunc, /* callback */ LPARAM lParam); /* app-defined value */ El tipo WNDENUMPROC se define a su vez como un tipo

puntero a función cuyo prototipo es el siguiente:

BOOL CALLBACK EnumWindowsProc( HWND hwnd, // handle to parent window LPARAM lParam ); // app-defined value Una callback se define con JNIEasy como una clase que

deriva de CCallbackImpl (en el caso de C), que

implementa el método: Object onCall(Object[] params), dicho método es el que será llamado cuando

la callback sea invocada desde código nativo.

public class EnumWindowsProc extends CCallbackImpl { private static final CMethodSignature SIGNATURE =

SignatureUtil.newCMethodSignature( int.class,new Class[]

Actas del II congreso javaHispano

62

Page 63: Actas del II congreso javaHispano

{int.class,int.class}, CallConv.STD_CALL );

public EnumWindowsProc() { super(SIGNATURE); } public Object onCall(Object[] params) { int hwnd =

((Integer)params[0]).intValue(); int lParam =

((Integer)params[1]).intValue(); System.out.println("handle:" + hwnd +

" param:" + lParam); return new Integer(1); } } Invocaríamos EnumWindows por ejemplo:

method = user32DLL.addCMethod( "EnumWindows",int.class, new Class[] { EnumWindowsProc.class, int.class }, CallConv.STD_CALL ); method.callInt(new Object[]{ new EnumWindowsProc(),new Integer(10)}); Salida por pantalla:

handle:65784 param:10 handle:328538 param:10 ... Mientras el objeto callback esté en memoria es como si

la función “se creara” desde el punto de vista nativo,

cuando se pierde vía garbage collector pasa a ser

inaccesible (como si se destruyera código máquina)

liberando automáticamente sus recursos. El número de

callbacks en memoria es ilimitado. Detrás de las callbacks

de JNIEasy está una compleja mezcla de JNI, Java y

código máquina generado dinámicamente desde Java.

Existe la posibilidad de que la definición de la función

que define una callback sea autónoma de JNIEasy, para

ello se usa Java Reflection, en donde un objeto callback

interno de JNIEasy “representa” la función “normal” de

Java. Sea por ejemplo:

public class EnumWindowsProc2 { public static int enumWindows(

int hwnd, int lParam) { System.out.println("handle:" + hwnd +

" param:" + lParam); return 1; } } java.lang.reflect.Method reflMethod = EnumWindowsProc2.class.getDeclaredMethod(

"enumWindows", new Class[]{int.class,int.class} ); CCallback callback = CallbackUtil.newCCallback(reflMethod);

method.callInt(new Object[]{callback, new Integer(10)});

5.6 Estructuras

La definición de estructuras es donde JNIEasy se

distancia claramente de las soluciones existentes, y en

donde entra a fondo la AOP y el bytecode enhancement.

Con ambas técnicas conseguimos “extender” una clase

normal Java para que represente a una estructura nativa,

introduciendo de forma ortogonal, el “aspecto” de la

gestión de los atributos para que representen a la

imagen de una estructura C.

Ejemplo, sea la estructura Win32 C:

typedef struct tagPAINTSTRUCT { HDC hdc; // HDC = int en Win32 BOOL fErase; // BOOL = int en Win32 RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32]; } PAINTSTRUCT, *PPAINTSTRUCT; En Java:

public class PaintStruct { int hdc; int fErase; Rect rcPaint = new Rect(); // Es embebido int fRestore; int fIncUpdate; byte[] rgbReserved =

new byte[32]; // Es embebido } Rect sería una simple clase Java con cuatro enteros

como atributos. En un archivo XML se indicaría además

que el atributo rcPaint y rgbReserved son

embebidos (no RECT* o BYTE*). Finalmente la

sentencia:

PaintStruct ps = new PaintStruct(); supone la reserva en “memoria nativa” de una estructura

C equivalente, la referencia ps puede usarse en aquellas

funciones donde se pida un PAINTSTRUCT*. Si se

modifica desde Java hdc, por ejemplo, se modifica

Actas del II congreso javaHispano

63

Page 64: Actas del II congreso javaHispano

también en la memoria nativa, un programa C/C++

puede modificar ¡en cualquier momento! (no sólo

dentro de una llamada iniciada desde Java) el atributo

hdc , percibiendo ese cambio en Java cuando se acceda

al mismo. La interacción transparente memoria Java-

memoria nativa es una de las características más

avanzadas de JNIEasy.

Por supuesto el ciclo de vida de la estructura vista desde

C es el mismo que el objeto Java, por lo que el garbage

collector se convierte en el “delete” o “free()” de las

aplicaciones basadas en JNIEasy evitando los consabidos

memory leaks de los que han estado plagadas las

aplicaciones C/C++.

Conseguimos en resumen una programación “nativa”

con Java, con filosofía Java y con mayor robustez y

seguridad que usando un lenguaje nativo.

5.7 Exportación de funciones

Una de las características más interesantes es la

capacidad de acceder directamente al método de una

callback desde código nativo sin JNI y sin conocer la

dirección de memoria previamente. Se mimetiza así la

exportación de un método de una DLL pero ¡desde Java!.

Sea el código Java:

public class CallbackTest { public static long suma(int a,int b) { return a + b; } } reflMethod = CallbackTest.class.getDeclaredMethod( "suma",new Class[]{int.class,int.class}); JNIEasyLibrary dll = JNIEasy.getInstance().getJNIEasyLib(); dll.exportMethod(reflMethod,

CallConv.STD_CALL);

Sea el siguiente código C/C++:

HMODULE dllHandle = ::LoadLibrary("JNIEasy.dll"); void* (__stdcall *findCBAddress)(

const char*); findCBAddress = (void* (__stdcall *)( const char*))::GetProcAddress(dllHandle, "_findExportedMethodAddress@4"); const char* sig =

"CallbackTest.suma(int,int)";

// signatura de la callback Java __int64 (__stdcall *suma)(int,int); suma = (__int64 (__stdcall *)(int,int)) findCBAddress(sig); __int64 res = suma(1,2); llama desde código nativo al método Java exportado

como si fuera un método C “normal”.

5.8 C++

JNIEasy también aporta herramientas para acceder a

métodos C++ en DLLs, clases Java emulando clases

C++ cuyos métodos y atributos “normales” pueden ser

visto como métodos y atributos “C++” etc.

6 ¿Hacia un desktop “muy” Java?

El tiempo lo dirá, JNIEasy es un paso más en esa

dirección.

Referencias

[1] JNIEasy. http://www.jnieasy.com

[2] Microsoft domina el mercado de sistemas operativos, pese al éxito de Linux. Dealer World, 09/10/2003 http://www.idg.es/dealer/actualidad.asp?id=32481

[3] JDesktop Integration Components. https://jdic.dev.java.net/

[4] Java Media Framework. http://java.sun.com/products/java-media/jmf/

[5] JNIWrapper. http://www.jniwrapper.com

Actas del II congreso javaHispano

64

Page 65: Actas del II congreso javaHispano

Guasaj. Un framework de programación basado en componentes

Benito Mateo, UrkoGolf Enparantza, Nº 1, 3 A

C.P. 20.160 Lasarte (Gipuzkoa) [email protected]

Blesa Jarque, ÁngelPlaza del Olmo, Nº 5, 2º Piso

C.P.44770 Escucha (Teruel) [email protected]

Lop lis, José JavierIsabel la Católica, Nº 16-18, Piso

5 C,Esc. Izq.

C.P. 50009 Zaragoza [email protected]

Abstract

En el ciclo de vida de un proyecto, independientemente del

proceso de desarrollo que se utilice (RUP, FDD, XP, etc…) en

un determinado momento se debe pasar del análisis de los

requisitos al diseño e implementación del mismo.

Los patrones de diseño hacen colaborar un conjunto de

clases e instancias de las mismas, para solucionar un

problema determinado permitiendo obtener una solución con

buenas características de acoplamiento, cohesión,

granularidad, rendimiento, adaptabilidad, evolución, etc. , pero

con los patrones de diseño sólo no basta, no dicen

directamente que modelo superior crear para hacer colaborar

N paquetes de casos de uso, y que permanezcan

desacoplados, independientes, reutilizables, etc..

En la búsqueda de este modelo superior surge el componente

de software como unidad independiente, cooperativa,

desacoplable, etc.

Lo que pretendemos con este proyecto es proponer una

metodología de organización de código en torno a

componentes con una estructura basada en patrones de

diseño bien conocidos(MVC, Observer, ViewDispatcher,

Factory, Command, Facade, VO, Service Activator , Service

Locator, …) que nos lleve del análisis de los casos de uso

(historias, requisitos funcionales, casos de aplicación, etc…)

a la implementación de la solución en código de una manera

metódica, repetible y con resultados reutilizables en

diferentes proyectos..

Keywords: framework, patrón, componente, metodología.

1 Motivación. Origen de guasaj.

El origen desde el cual guasaj fue concebido fue crear un

entorno de trabajo en el cual se defina un procedimiento

para plasmar el análisis y diseño de la solución de un

problema en un conjunto de componentes reutilizables.

Con ello se pretende aumentar la productividad a través de

dos cuestiones:

• El establecimiento de un procedimiento claro de

implementación de las funciones descubiertas en el

análisis y el diseño.

• La reutilización automática del trabajo realizado en el

paso anterior.

En primer lugar se pretende crear un esquema de clases

sencillo para la implementación de componentes, con un

ciclo de vida, en la llamada a sus servicios, lógico y que

cumpla las premisas de los patrones de diseño

sobradamente conocidos [1] (MVC, command, service

locator, factory, etc…). A través del estudio de la filosofía de

creación de aplicaciones basadas en componentes pasar a

una implementación de la misma, sencilla, pero potente y

flexible, creando una asociación rápida y semiautomática

entre el modelo conceptual de una aplicación y su

correspondiente implementación.

Con este proceso se pretende eliminar, dentro de lo posible,

el problema de tener que “reinventar la rueda” en cada

proceso de análisis y diseño de un determinado problema,

muchas veces supeditado a la imaginación e inspiración en

el diseño final del arquitecto/diseñador/programador.

Otro de los factores o puntos de especial interés radica en

el hecho de establecer una definición, implementación,

manejo, capacidades, y ciclo de vida de los componentes,

de tal manera que todo el equipo de desarrollo emplee el

mismo idioma.

Actas del II congreso javaHispano

65

Page 66: Actas del II congreso javaHispano

En definitiva, ir un paso más allá de los patrones de diseño

en el establecimiento de un lenguaje común para la

nomenclatura de las funciones, comportamiento y

arquitectura de un sistema.

2 Problemas detectados en el desarrollo deprogramas en la actualidad

En la labor de desarrollo de proyectos software se

presentan una serie de problemas con demasiada

frecuencia, como son:

• Dificultad en el paso de análisis, al diseño y

codificación. La identificación y agrupación de las

funcionalidades del sistema en paquetes y su posterior

paso a codificación no está suficientemente

sistematizado.

• Poca o ninguna aplicación de patrones de diseño para

resolución de problemas genéricos en los proyectos

cotidianos, debido en parte a la dificultad para abstraer

la problemática concreta de un gran proyecto, a las

soluciones a un nivel más micro que aportan los

patrones de diseño. Se hace complicado pasar de

pequeñas implementaciones de soluciones en una serie

de clases y objetos aplicando unos determinados

patrones, a la implementación de una serie de paquetes

o componentes que desarrollen una parte concreta,

independiente, reutilizable, extensible y configurable de

la aplicación de un tamaño considerablemente mayor.

• No existe una separación clara entre la vista de la

aplicación y el modelo, sucumbiendo en la mayoría de

las veces ante la dificultad de disociar las distintas

porciones de código que participan en una parte de la

solución, interface gráfico, eventos del GUI, validación

de datos, acceso a datos persistentes , etc …

• Dificultad de programación para el interface en lugar de

la implementación.

• Mala gestión de la creación – instanciacion de objetos

tanto para ejecutar la lógica del sistema, como para

representar el estado del mismo en un momento dado.

• No se define una separación clara entre al estructura de

datos que almacenan el estado del sistema en cada

momento de ejecución del mismo, y las diferentes

operaciones que se pueden realizar sobre dichos datos.

No existe, en general, un procedimiento sistemático para

codificar la funcionalidad que se requieren (casos de uso,

historias, requisitos arquitectónicos, características

funcionales y no funcionales, etc), de tal manera que

mantengamos desde el principio un separación entre vista y

modelo, una gestión clara de los datos del proceso, un

manejo de excepciones efectivo, y una posibilidad de

reutilización practica y rápida, desde el principio, de la

codificación, de tal manera que la exportación de

funcionalidades desde un proyecto a otro sea automática.

3 Del análisis a la programación. Pasos ytrabas intermedias

En cualquiera de las metodologías o procesos de desarrollo

de software, salvando sus peculiaridades, se sigue un

proceso similar al que se describe a continuación para la

consecución de la solución a un proyecto:

• Estudio de los requisitos.

• Análisis de la solución. Modelo conceptual.

Descubrimiento de las entidades del problema.

Agrupación en paquetes conceptuales.

• Diseño de la solución. Patrones. Establecimiento de la

arquitectura. Diseño de pruebas. Cumplimiento de

requisitos no funcionales, etc…

• Codificación. Llegado este momento en determinadas

metodologías podemos estar en un estado más o menos

avanzado en la identificación de clases y métodos a

implementar, pero en general se dista bastante de tener

una visión clara y lo más importante, acertada y con

posibilidades de ser la definitiva. Esto deriva en una

lógica de negocio más o menos dispersa en métodos de

clases cuyas responsabilidades no están claramente

definidas. Esto puede llevar a gravísimos problemas de

acoplamiento entre partes funcionales del sistema,

difíciles de independizar a posteriori, siendo muy difícil

cuando el modulo en cuestión tiene ya un tamaño

considerable y nos percatamos de las limitaciones

impuestas, pensar en una refactorización del diseño que

no nos provoque más de un dolor de cabeza y desde

luego una merma en nuestra productividad.

3.1 Solución. Aplicación de patrones

Los patrones nos aportan buenas prácticas de código, en la

pequeña escala, para salvar de una manera óptima y muy

probada circunstancias que se dan en la programación

cotidiana.

El uso de patrones hace que las porciones de código

resultantes sean robustas, flexibles, extensibles, adaptables,

optimizadas y fiables, de tal manera que el conjunto de la

aplicación también herede dichas cualidades. Esto es lo que

se pretende pero en el camino para lograrlo se tiene una

Actas del II congreso javaHispano

66

Page 67: Actas del II congreso javaHispano

serie de imponderables, que hacen que las decisiones de

diseño no sean triviales.

En el momento de diseñar la solución para una aplicación el

arquitecto/diseñador debe tener una concepción de las

entidades y la colaboración entre las mismas que le harán

desempeñar la solución requerida, así como una capacidad

de abstracción para descubrir entre estas entidades la

problemática que encierran y que parte de ésta, está

contemplada como patrón sobradamente conocido.

3.2 Problemática de los patrones en lacodificación

El uso de patrones de diseño en la solución de una

aplicación facilita el paso del diseño a la implementación por

estar estos ya codificados en multitud de ocasiones. Aún

así, hay un nivel de abstracción intermedio en las soluciones

genéricas que aportan los patrones, y los problemas de

modelado, diseño, empaquetado, y reutilización de código

que se necesitan en los proyectos con una tamaño

considerable, sobre todo en sistemas en los que se

desarrollan una serie de aplicaciones (suite) para dar una

serie de servicios integrales a una empresa.

La solución puede pasar por la elaboración de un

framework que encapsule las buenas prácticas de los

patrones sobradamente conocidos y haga que los

programadores sean capaces de representar el modelo

lógico de la solución del problema, expuesto en el análisis,

con un buen diseño, una buena arquitectura y un código

ampliamente reutilizable sin tener que implementar

físicamente los patrones, sino que sea el framework el que

maquille para el desarrollador final el uso de los mismos.

Dicho de otra manera, el hecho de programar bajo este

framework garantiza la herencia de la mayoría de los

patrones de diseño más utilizados, sin prohibir en absoluto

la implementación de alguno de los mismos para cubrir una

determinada necesidad.

4 Condiciones deseadas en la solución

Un framework que pretendiese implementar una solución

para la problemática anteriormente descrita deberá poseer

una serie de características como:

• Guiarse por un patrón de comportamiento como el MVC

para la separación de vista, modelo y controlador.

• El código resultante debe quedar en forma de

componente reutilizables, y cumplir con el paradigma y

filosofía de construcción de aplicaciones basadas en

componentes tal y como se detalla más en profundidad

en [2].

• El cliente de un componente estará desacoplado del

mismo, ni siquiera a través de una interface. La

resolución del componente y del método a ejecutar se

realizará en tiempo de ejecución

• Los componentes que participan en una aplicación, la

descripción de los mismos en cuanto a comportamiento

y aspectos (acceso, relaciones, vista, excepciones, log)

debe tener un soporte de configuración exterior al

código (archivo xml de configuración).

• Los componentes deben permitir la ejecución

secuencial de dos métodos de distintos componentes, o

desde uno de estos a otro. El hecho de que un método

de un componente sea llamado desde otro puede

provocar en determinadas circunstancias que la

respuesta de éste sea de un tipo o de otra

• Un componente tiene una lógica de negocio

representado por un BO (Bussiness Object) con los

métodos operativos, y además un componente trabaja

con un conjunto de datos en forma de VO (Value

Object).

• El estado en memoria de un componente en un

determinado momento de ejecución (por ejemplo, un

servidor de Chat, con una serie habitaciones y unos

usuarios en las mismas, en un determinado momento)

se debe reflejar en este BO. Pero no una instancia del

BO por cada elemento a reflejar. Por ejemplo, el

componente “Habitación” en una aplicación de chat,

estaría formado por un BO con las operaciones y una

lista de posibles habitaciones.

• De esta manera un componente será gestor y almacén

de los datos que puede manejar. Los componentes son

elementos de peso de tal manera que en el sistema no

tendremos múltiples instancias de un componente[1],

sino que será el componente el que maneje los datos

necesarios y trabaje con las operaciones para construir

y manejar el estado del sistema en un momento dado.

• Cuando en una vista de un componente se lleve a cabo

un cambio, dicho cambio deberá ser reflejado de alguna

manera en el estado de la lógica del componente, en su

BO, es decir, un cambio en una de las vistas se ve

reflejado en su homónimo del modelo. Por ejemplo,

cuando en un componente gestor de barra de

herramientas seleccionamos un elemento y desde otro

componente, queremos acceder al elemento

seleccionado. No podemos desde una vista de un

componente acceder directamente a la vista de otro,

Actas del II congreso javaHispano

67

Page 68: Actas del II congreso javaHispano

debemos pasar por el modelo y solicitar algún atributo

que nos de la información que requerimos.

5 Características de los componentesguasaj

Un componente guasaj es un conjunto de clases diseñadas

para llevar a cabo una serie de funciones relacionadas con

un problema del modelo de negocio del sistema o

desarrollar una función de carácter más amplio dentro de la

arquitectura, estando este acompañado de un fichero de

descripción de las características y posibilidades de

ejecución de dicho componente. Ejemplo, roles de usuario,

pre y post ejecuciones, controlador de excepciones,

métodos virtuales…

Un componente guasaj es autocontenido en su ciclo de vida,

llevando a cabo una separación entre lógica de negocio y

datos, así como vista y modelo. En un principio la

plataforma objetivo de guasaj es la J2SE aunque su filosofía

es extrapolable tanto a J2EE como J2ME. Todo

componente aporta un mecanismo de llamada a sus

servicios, un método de gestión y acceso a sus datos, así

como un control de sus vistas, manejo de excepciones y

control de acceso.

Dentro de los tipos de componentes que podemos

desarrollar se pueden encontrar 2 tipos principales con sus

peculiaridades y variantes:

Componente entidad: Son componentes que intentan

representar el modelo lógico de negocio propio de un

proyecto asumiendo una serie de características de la

solución final. Estos componentes desarrollan una función,

tienen una responsabilidad y unos mecanismos o reglas de

interacción con otros componentes de entidad o de servicio.

Un ejemplo de componente representativo de una entidad

del modelo de negocio podría ser los componentes cliente,

factura, proveedor, empresa, albarán, etc... por ejemplo, en

una aplicación de gestión. En un sistema de tratamiento de

señales provenientes de un sistema de instrumentación

electrónica, estos pudieran ser, equipo, señal, punto de

medida, etc. En general los candidatos a este tipo de

componentes pueden ser los provenientes del análisis

conceptual del dominio del problema.

Componentes genéricos de servicio: Componentes que

permanecen completamente independientes de las

peculiaridades de un determinado proyecto siendo

totalmente reutilizables en otro ámbito de ejecución e

incluso plataforma, si están diseñados para ello. Por

ejemplo, un componente para comunicaciones TCP (cliente

y servidor), un componente para selección y gestión del

idioma para una aplicación, un componente manejador del

estilo y fuentes de una aplicación, un componente

calendario, un componente calculadora, etc…

De esta manera en la elaboración de una solución

completa para un problema, partiremos del modelo

tradicional de resolución de problemas software, de la

siguiente manera:

• Se plantea una serie de requisitos o funcionalidades a

desarrollar.

• Se lleva a cabo un análisis funcional y se determina un

modelo conceptual en el que se descubren entidades,

relaciones entre estas y atributos de las mismas.

• Se realiza una agrupación en paquetes guiándose por

una determinada premisa pudiendo esta ser,

agrupación por función, agrupación por complejidad,

agrupación por arquitectura, agrupación por

departamento lógico del cliente, etc, etc.. Suele ser en

este momento donde empiezan a surgir los problemas

separación de responsabilidades entre las entidades del

sistema. Aquí evidentemente no hay magia que valga,

la decisión final de agrupación, separación de

responsabilidades de cara a un diseño u otro es propia

del arquitecto /diseñador, siendo muchas veces

equivalentes soluciones con topologías de entidades

diferentes.

Una cuestión que puede y debería ayudar sobremanera en

este paso del proceso de desarrollo, sería el hecho de saber

exactamente el procedimiento de codificación que

seguiremos para llegar a implementar esta entidad, e

igualmente los servicios a los que tendremos acceso sólo

por el hecho de implementar la entidad de acorde a este

procedimiento / framework de programación.

La idea radica en crear una equivalencia entre cada uno de

los términos utilizados en el análisis funcional de la

aplicación y la codificación de los mismos. Saber medir que

implicaciones tendrá el hecho de utilizar palabras como

paquete, clase, entidad, atributo, relación, caso de uso,

servicio, etc.… en la codificación del sistema.

6 Introduciéndonos en guasaj

De esta manera y según lo expuesto fundamentos de los

cuales parte el desarrollo de guasaj son:

• Separación en modelo, vista y controlador.

Actas del II congreso javaHispano

68

Page 69: Actas del II congreso javaHispano

• Independencia de componentes.

• Variación del comportamiento de un componente según

una definición exterior, sin modificar el código.

• Estandarizar la nomenclatura y tipo de clases al crear

un componente reutilizable.

• Crear un elemento amigable tanto para el analista como

para el programador del sistema, pasando por el

arquitecto y el diseñador.

6.1 Localización de componentes pornombre.

Para tener acceso a los servicios de un componente

debemos primero localizar una instancia de dicho

componente. Para ello, pasaremos un nombre único con el

que denominaremos unívocamente a un componente dentro

de la aplicación y estará referido en el fichero de descripción

guasaj y del componente.

Una vez localizado un componente y apuntado por una

interfaz común para todos podremos llamar a los servicios

que implementa.

6.2 Ejecución de métodos de loscomponentes dinámicamente.

Resolución de los métodos a ejecutar según la firma del

método, nombre y paso de parámetros, pudiendo derivar en

diferentes comportamientos en la ejecución y la respuesta

según los parámetros pasados.

6.3 Posibilidades de redirección a la vista.

Cuando se llama a un método de un componente, se quiere

llevar a cabo una funcionalidad y generalmente obtener un

resultado de la misma, acompañada de una visualización de

los resultados. Otras veces, se quiere ejecutar la lógica de

modelo pero no se quiere visualizar el resultado de la misma

a nivel de interface gráfico, sino que sólo se quiere manejar

los datos del resultado de la operación. De esta manera se

puede elegir en el momento de la llamada a un método de

un componente si queremos ejecutar la parte de vista

vinculada a ese método o no. Igualmente, podemos indicar

en el momento de la llamada qué método y de qué

componente queremos que se haga cargo de manejar la

respuesta en forma de vista de ese método. Y aún hay más,

podemos decirle en que instancia de dicha vista queremos

que se ejecute el método de respuesta, en el caso de que

manejemos diversas instancias de vista de la misma clase.

Con todo lo anteriormente expuesto, tenemos tres

funciones relacionadas con la vista:

• Primero, indicar si queremos manejar vista o no.

• Segundo, indicar que método de que componente

queremos que maneje la respuesta en forma de vista.

• Tercero y último, si para ese componente queremos

instanciar una nueva vista o manejar una que pasamos

en la llamada al método. Tres en uno.

Así, teniendo la ventaja de una separación entre

componentes, podemos acceder a través de las funciones

del contenedor (éste las resuelve en tiempo de ejecución,

no de desarrollo), a otros componentes para pasarles

(notificarles) resultados de operaciones de otros

componentes. Esto corresponde con la teoría de inversión

de control [3], por la cual es el contenedor el que llama a

nuestras clases para realizar ciertas funcionalidades en un

momento dado.

6.4 Posibilidad de llamar a métodos nobloqueantes.

Sin tener que esperar a que termine la ejecución del método

llamado. Esta utilidad resulta interesante cuando queremos

tener un mecanismo automático de ejecución en segundo

plano de una operación y recibir la respuesta de esta

cuando finalice la misma, sin que tengamos por ello

bloqueado el flujo principal del programa, esperando

retornar de la llamada efectuada. Un ejemplo concreto de

esta funcionalidad seria la localización remota de un servicio

o componente que puede llevar unos segundos. Es posible

que no podamos seguir la ejecución de algo concreto sin

este componente o servicio pero eso no impide que

podamos ejecutar otras opciones del programa y ser

avisados cuando se haya localizado el componente o

cuando haya vencido el plazo de timeout.

6.5 Concentración del manejo deexcepciones.

A través de un HandlerException por componente.

Mecanismo por el cual las excepciones producidas son

dirigidas a un método de una clase que se ocupa de su

gestión y tratamiento. También existe la posibilidad de

definir si el trato de excepciones se procesa en el

componente original o si se redirecciona a otro manejador

en el proyecto destino (ya que dependiendo de cómo y

dónde se ejecute un componente puede que no queramos

ni deseemos su tratamiento original o incluso necesitemos

capturar las excepciones producidas por un componente y

tratarlas a nuestro modo).

Actas del II congreso javaHispano

69

Page 70: Actas del II congreso javaHispano

6.6 Control de acceso a los métodos ycomponentes por rol de usuario.

A través del fichero de descripción del componente se

puede indicar que roles de usuario tendrán acceso a cada

método. Lo único que se debe realizar es activar en el

contenedor guasaj el rol de usuario activo. En tiempo de

ejecución comparará si el rol activo coincide con alguno de

los que tiene permiso de ejecución. El proceso común será

aprovechar el momento en el que pidamos validación al

usuario para recoger de este el rol de usuario y activarlo en

guasaj. Para este usuario cuando ejecute el resto de

operaciones su nivel de acceso vendrá determinado por

dicho rol.

6.7 Métodos virtuales.

Son métodos que no está implementados en el componente

original, sino que estarán redireccionados a otro método de

otro componente que será el que realmente se ejecute,

recibiendo los parámetros originales. Esta función es

necesaria para permitir que las llamadas a métodos

realizadas desde el “interior” del componente puedan ser

capturadas y manejadas por otro componente. Por ejemplo,

tenemos un componente que gestiona conexiones TCP,

atiende a los clientes conectados, y recibe peticiones de los

mismos. Este componente es reutilizable en multitud de

proyectos, pero no sabemos en tiempo de implementación

del componente que método de que clase tenemos que

llamar cuando recibamos una trama, ya que,

evidentemente, dependerá de lo que queramos hacer con la

misma en el proyecto que nos ocupe. Para ello podemos

definir un método virtual en este componente, receiveData,

que será invocado por cada hilo gestor de un cliente

conectado, para indicar que nos ha llegado una trama de

datos. En el fichero de descripción de componente

indicaremos que éste método es virtual y qué método de

qué componente queremos que se ejecute cada vez que se

llame a dicho método virtual.

6.8 Preejecución, postejecución eintercepción de métodos.

En la descripción de un método, dentro del archivo de

configuración del componente, podemos especificarle un

método que se ejecutará antes que este. Este último recibirá

los parámetros del método original para su ejecución. En el

caso de queramos una postejecución, podemos definir un

método que se ejecutará con posterioridad a la ejecución

del método original. En este caso este método recibirá tanto

los parámetros del método original como la respuesta

producida por este. Y por último, en el caso de la

intercepción, el método interceptor recibe los parámetros del

original, puede modificar los mismos, y llamará al método

original con éstos. Un ejemplo de preejecución, puede ser

incluir un sistema de logs a un determinado método. En el

caso de la postejecución, un posible ejemplo sería la

elaboración de un informe al término de la ejecución de un

método, necesitando para ello, los parámetros de entrada,

respuesta del método original y los posibles cambios que

haya podido originar dicha llamada, como escritura en base

de datos, cambios de estado, alteración de ficheros o

configuraciones, etc…

Y por último, un ejemplo de intercepción sería el hecho de

dotar de un sistema de cifrado a un mensaje pasado entre

componentes. Podríamos capturar los datos de la llamada

original, cifrarlos o descifrarlos y continuar con la llamada en

el componente destino que se ejecutaría ya con los datos

cifrados o descifrados.

Los métodos, pre, post e interceptor son ejemplos claros de

componentes que dotan una funcionalidad añadida no

contemplada anteriormente en el sistema.

7 Otras consideraciones en loscomponentes guasaj

Los componentes guasaj están concebidos desde un

principio con una vocación de reutilización de los mismos en

diferentes ámbitos y soluciones informáticas, sin por ello

acarrear un malus de productividad para el usuario final de

los mismos como desarrollador de aplicaciones guasaj. Al

contrario al pensar directamente en la reutilización del

trabajo realizado se tienen en cuenta desde las fases más

tempranas de codificación unas características de

arquitectura y diseño muy positivas. La clave de todo este

proceso resulta en no crear una abstracción vacía de

elementos software de difícil implementación sino todo lo

contrario, dotar de un framework que nos haga una gran

parte del trabajo de nomenclatura de nuestras clases,

separación de responsabilidades, posibilidades de relación

entre componentes y acceso a los servicios de los mismos

desde cualquier parte de la aplicación.

8 Conclusiones

En la ejecución de un proyecto software, el paso del análisis

del problema al diseño y codificación presenta una serie de

dificultades para asignar las diferentes responsabilidades

entre las unidades de código que vamos creando. Dentro de

las unidades de código queremos mantener una separación

entre la lógica de negocio y la vista. Gran parte del código

que generamos para la solución de un determinado

problema deberíamos poder reutilizarlo en parte o por

completo, con alguna pequeña variación de configuración

Actas del II congreso javaHispano

70

Page 71: Actas del II congreso javaHispano

en otros proyectos, dentro del mismo ámbito o no. El

componente guasaj nos permite crear estructuras de código

que desarrollen un conjunto de funciones reutilizables en

otros proyectos. Los patrones de diseño por si mismos no

establecen un lenguaje suficiente para la nomenclatura de

la funcionalidad, comportamiento y arquitectura de un

sistema. Debemos ir hacia una entidad de mayor calibre

que cubra esta necesidad.

Resulta fundamental definir un conjunto, framework -

procedimiento, que automatice el proceso de codificación

del sistema, sin depender en exceso de la inspiración

particular, para llegar a lograr un diseño arquitectónico

correcto, repetible y reusable, todo ello en aras de una

mayor productividad y calidad software.

Agradecimientos

Queremos agradecer a la EUPLA la posibilidad de contribuir

a este congreso con el desarrollo de este trabajo.

Igualmente a ARCO ELECTRÓNICA S.A, las facilidades

para la realización del mismo, y la asistencia a este

congreso. También un agradecimiento especial para Sergio

Gil García por contribuir en los inicios de esta idea.

Y en especial a la comunidad javaHispano por permitirnos

participar en este congreso.

Referencias

[1] Erich Gamma, Richard Helm, Ralph Johnson and JohnVlissides. Design Patterns. Element of Reusable Object-Oriented Software, Addison-Wesley, 1995.

[2] Claudia Patricia García Zamora y Samuel Garrido.Programación basada en componentes. CINVESTAV MéxicoD.F 4 - Noviembre -2003.

[3] Mike Spille, Inversion of controlhttp://www.pyrasun.com/mike/mt/archives/2004/11/06/15.46.14/index.html

Actas del II congreso javaHispano

71

Page 72: Actas del II congreso javaHispano

Actas del II congreso javaHispano

72

Page 73: Actas del II congreso javaHispano

Extensión del patrón Observador para la integración de eventos decomponentes heterogéneos.

Luis Rodero MerinoUniv Rey Juan Carlos, [email protected]

Miguel A. Ortuño PérezUniv Rey Juan Carlos, DIET

[email protected]

Luis López FernándezUniv Rey Juan Carlos, [email protected]

Abstract

En este artículo presentamos una extensión al ya conocido

patrón Observador. Esta extensión está orientada a

facilitar la monitorización de eventos provenientes de

distintos componentes de un sistema. Este artículo también

contiene un ejemplo de como aplicar este patrón dentro

del contenedor PicoContainer.

Palabras clave: Observador, observable, patrón,contenedor, componente.

1. Introducción

El patrón Observador es uno de los más ampliamente

utilizados en la programación de sistemas, aunque a

veces incluso el programador no sabe que lo está

usando. Hay dos roles básicos en este patrón: el

componente observable, que lanza eventos para

notificar cambios en su estado, y el observador que

espera y recibe esos eventos.

El API estándar de Java [3] contiene la interfaz

java.util.Observer y la clase abstracta

java.util.Observable, que pueden ser usadas como base

para la implementación de este patrón. Aunque como

veremos más adelante, esta solución es muy limitada

cuando se necesita manejar notificaciones desde

distintos componentes dentro del mismo sistema, cada

uno capaz de generar sus propios eventos.

Este artículo muestra una extensión del patrón

Observador que simplifica el manejo de distintas fuentes

de eventos dentro de un sistema. El artículo comienza

con una definición más completa y profunda del patrón

Observador, y describe sus limitaciones, mostrando las

dificultades que pueden surgir al usarlo. Después se

explica la extensión que hemos desarrollado,

comentando sus ventajas y cómo aplicarla. Finalmente

mostramos un posible uso de esta extensión aplicándolo

dentro del contenedor de componentes PicoContainer.

2 El patrón Observador

El patrón Observador es uno de los 23 patrones

descritos en [2]. Este patrón “Defines a relationship

between a group of objects such that whenever one

object is updated all others are notified automatically”.

El objeto observado no necesita saber nada acerca de los

observadores. Son los observadores quienes deben

registrarse como 'oyentes' para poder recibir eventos.

Esto permite el desarrollo de aplicaciones con

componentes poco acoplados. el bajo acoplamiento se

considera una ventaja ya que simplifica la posterior

reutilización de componentes.

Los oyentes reciben notificación de todos los eventos

generados en los objetos observados. Pueden registrarse

en cualquier momento durante el ciclo de vida del

componente.

Este patrón debe aplicarse cuando:

• Cambios en algunos de los objetos del sistemarequieren cambios en otros objetos del mismo grupo.

• El número de oyentes puede variar durante el ciclo devida del objeto.

• El bajo acoplamiento es un requerimiento básico deldiseño..

Este patrón implica dos roles distintos, como se muestra

en la Figura 1.

El patrón es bastante sencillo, y puede encontrarse como

parte de otros patrones más complejos tales como el

patrón Modelo Vista Controlador, donde el controlador

es un observador que recibe eventos de la interfaz, y la

vista recibe eventos referidos a cambios en el modelo.

Actas del II congreso javaHispano

73

Page 74: Actas del II congreso javaHispano

3 Desventajas del patrón Observador

Debido a su sencillez, el patrón Observador tiene

algunas desventajas:

• Todos los oyentes reciben todos los eventos lanzados, sindistinción. Esto es ineficiente, y los observadoresdeberían ser capaces de registrarse sólo para aquelloseventos en los que estén interesados.

• A menudo los sistemas tienen varios componentes queson generadores de eventos, y varios componentes queescuchan por esos eventos. Las relaciones entre todosestos componentes pueden ser difíciles de maneja. Verpor ejemplo la Figura 2

Gamma et al. [2] ya sugerían utilizar un mediador

(patrón Mediador [2]), llamado Gestor de Cambios. El

mediador mantiene las relaciones entre oyentes y

componentes observados (Figura 3).

El Gestor de Cambios puede ser un gestor sencillo, que

sólo reenvíe eventos desde cualquier objeto observable a

todos los observadores. Pero también puede ser más

complejo, guardando información acerca de qué eventos

interesan a qué observadores. En ese caso, el Gestor

reenviaría a cada oyente sólo los eventos por los que

está interesado.

Esta solución, aunque más potente, también presenta

problemas:

• Los oyentes aún necesitan saber los componentes quedeben observar, aunque es posible que sólo sepan loseventos que quieren recibir. Si el oyente es uncomponente externo al sistema, entonces es posible queno sepa cuales son esos componentes.

• En algunos casos, puede que no todos los observadoresdeban ser informados acerca de todos los eventos queocurren en el sistema, incluso aunque estén interesadosen ellos, por razones de seguridad o rendimiento.

• Si los observadores tardan un tiempo apreciable enprocesar eventos, el rendimiento del sistema puede verseafectado. Este hecho se agrava si los componentes sonexternos al sistema.

• Si se generan muchos eventos, el tiempo para crearlos yreenviarlos puede ser no despreciable. Esta circunstanciase agrava cuando se utiliza un estrategia push para latransmisión de la información referida al evento. Estosignifica que el evento transporta toda esta información,por ejemplo el nuevo estado del componente observado.Para solucionar este problema debería ser posible fijarlos eventos que deben ser creados y los que deben serignorados.

• La implementación de políticas referidas al manejo deeventos no es una tarea trivial, ya que puede implicar eltrabajar con componentes y oyentes repartidos a travésde todo el sistema.

• Java no implementa herencia múltiple. Por lo tanto,muchas clases no serán capaces de heredar dejava.util.Observable ya que ya tienen otra clase padre.

Para concluir, hay otro problema que aparece en un

ámbito bastante más concreto. Si se usa un contenedor

de componentes para hospedar las partes del sistema es

bastante probable que algunos componentes deseen ser

avisados acerca de eventos relacionados con el ciclo de

vida de otros eventos. Esto es, cuando son creados,

iniciados, parados... Sin embargo, no es posible asegurar

que todos los componentes mandarán los eventos

apropiados (puede que sean componentes 'importados'

al sistema y desarrollados por otros). Además, puede

discutirse si es el componente y no el contenedor quien

debe generar estos eventos.

4 Administrador de Eventos, Anunciantes

Los problemas descritos en la sección anterior fueron

detectados durante el desarrollo de un sistema peer to

Figura 1 Patrón Observador

Figura 2 Varios componentes observados yobservadores

Actas del II congreso javaHispano

74

Page 75: Actas del II congreso javaHispano

peer. Un requisito importante es que debíamos ser

capaces de monitorizar y registrar todo lo que ocurriera

en el nodo (eventos referidos a conexiones,

búsquedas...). Nos enfrentamos al problema de

monitorizar todos estos eventos, y concluimos que lo

mejor era utilizar un sistema de gestión de eventos

centralizado. Más adelante añadimos nuevas

capacidades al nodo, por ejemplo la posibilidad de fijar

filtros de eventos.

Para todo ello, hemos desarrollado una extensión del

patrón Observador, introduciendo Anunciantes y un

nuevo Administrador de Eventos que sustituye al Gestor

de Cambios.

4.1 Administrador de Eventos

El Administrador de Eventos sigue la misma idea que el

Gestor de Cambios explicado en la sección 3. Se sitúa

entre oyentes y componentes observables, y mantiene

las relaciones entre estos. Pero también añade algunas

capacidades nuevas:

• Un observador puede registrarse para recibir cualquierevento, sin especificar el componente que lo genera.Esto es, la administración se centra en eventos y no encomponentes.

• Pueden especificarse filtros de eventos. Si algún eventono pasa esos filtros, no es reenviado a los observadores.

• El Administrador de Eventos contiene una cola deeventos que puede ser activada al inicio. Los eventos sonalmacenados en la cola, y un hilo dedicado se encarga dereenviar los eventos de la cola a los oyentes.

4.2 Anunciantes

Un anunciante es un objeto asociado al componente

observable. El componente llamará su Anunciante

siempre que un nuevo evento deba ser notificado. El

Anunciante comprueba primero que el evento puede ser

reenviado, es decir, pasa los filtros (usa una llamada al

Administrador de Eventos). Si es así, la instancia del

evento correspondiente es creada y enviada al

Administrador de Eventos. Este notificará el evento a los

observadores

Este mecanismo tiene las siguientes ventajas:

• Los componentes no necesitan heredar de la clasejava.util.Observable.

• Los eventos que no pasen el filtro no son instanciados,mejorando por lo tanto el rendimiento..

• La administración de políticas está centralizada en unpunto.

En la Figura 4 vemos como los anunciantes se sitúan

entre el Administrador de Eventos y los componentes

4.3 Administración de eventoscentralizada

El uso de un Administrador de Eventos y un Anunciante

permite usar una implementación centralizada de la

gestión de eventos. Los programadores pueden

centrarse en la lógica de los componentes, ya que la

creación y reenvío de eventos son manejados por el

Anunciante correspondiente. Además, la administración

de eventos es facilitada ya que las tareas relacionadas

con los eventos se realizan en un único punto. Así, la

especificación de políticas referidas a notificaciones

(filtros, permisos...) puede hacerse llamando a los

métodos adecuados del Administrador de Eventos. Sin

este, la implementación de políticas es una tarea

complicada que implica trabajar con todos los

componentes observables.

Un Administrador de Eventos, o un componente similar,

podría estar presente dentro de un contenedor de

componentes. Así, el manejo centralizado de eventos

sería un servicio más proporcionado por dicho

contenedor. El contenedor a su vez podría también crear

notificaciones referidas a instantes del ciclo de vida de

los componentes.

Figura 3 Gestor de Cambios

Actas del II congreso javaHispano

75

Page 76: Actas del II congreso javaHispano

5 Administrador de Eventos en elcontenedor PicoContainer

En sistemas complejos, con un número grande de

componentes, es fácil encontrar muchas fuentes

posibles de eventos, así como observadores. Como se

explicó en la sección anterior, el manejo de las relaciones

entre observados y observadores y la implementación de

políticas referidas al reenvío de eventos son tareas

difíciles.

Sin embargo, utilizar eventos para la comunicación entre

componentes es una buena opción cuando se

desarrollan componentes con bajo acoplamiento.

Además, nuestra experiencia demuestra que es mucho

mejor y más factible utilizar eventos cuando se necesita

monitorizar el sistema desde un componente externo.

En los últimos años nuevos contenedores han aparecido

dentro del mundo Java. Aunque diferentes en

complejidad y capacidades, comparten el mismo

objetivo básico de facilitar el desarrollo de sistemas

mediante componentes. Las tareas básicas que suelen

realizar son:

• Instanciación y ensamblaje de componentes. El patrónInversión de Control es usado normalmente para estatarea. Las dependencias entre componentes sonautomáticamente resueltas por el contenedor.

• Mantenimiento del ciclo de vida de los componentes.

• Proporcionar servicios tales como logging,configuración...

• Servicios avanzados tales como pools de threads, fuentesde datos...

Por ejemplo, Avalon [1] es un plataforma para la

programación de componentes y contenedores. Uno de

sus proyectos hijo es el contenedor Merlin, que

proporciona varios servicios como los mencionados

antes. Otros contenedores tales como Spring [4], ,

NanoContainer [5]... están también disponibles para la

programación con componentes.

Sin embargo, no hemos podido encontrar ningún

contenedor que proporcione un servicio de manejo de

eventos como el descrito en la sección 4.3.

Por ello, hemos tomado el contenedor PicoContainer [6]

e intentado añadirle capacidades para la gestión de

eventos. Las razones por las que hemos elegido este

contenedor son básicamente dos:

• Es código de fuente abierta, que puede ser leído ymodificado.

• Es un contenedor sencillo. Sólo resuelve dependenciasentre componentes, y no proporciona ningún servicioextra. Esta simplicidad facilitó la comprensión y posteriormodificación de su código

5.1 Cambios realizados en PicoContainer

Hay dos cambios básicos que hemos realizado sobre el

contenedor.

Primero ,un Administrador de Eventos ha sido añadido.

Otras entidades puede acceder al mismo para fijar

políticas de filtrado, para registrarse como observador,

etc.

Figura 5 Diagrama de clases del Administrador deEventos y de los Anunciantes

Figura 4 Administrador de Eventos, Anunciantes

Actas del II congreso javaHispano

76

Page 77: Actas del II congreso javaHispano

Segundo, a todos los componentes se les asigna un

Anunciante que envía eventos referidos al ciclo de vida

del componente. Esto es, notifica cuando el componente

es iniciado, parado. Este Anunciante no es llamado por

el componente, sino por el mismo contenedor, que es el

que controla el ciclo de vida. Así el componente no

necesita heredar de ninguna clase, ni implementar

ninguna interfaz o llamar a ciertos métodos. No es

necesario cambiar el componente en absoluto, todo es

hecho automáticamente por el contenedor. Sin embargo

es posible que el componente quiera proporcionar su

propio Anunciante al contenedor, en el caso que tenga

su propia implementación. Por supuesto, cualquier

componente puede tener varios Anunciantes.

Para conseguir esto, hemos extendido la clase

DefaultPicoContainer para crear la nueva clase

PicoEventAbleContainer. Esta nueva clase mantiene las

relaciones entre componentes y Anunciantes. Los

Anunciantes manejados por este contenedor deben

implementar la interfaz PicoComponentAdviser, tal y

como se define en la Figura 6.

Cuando se instancia cualquier componente, si el

componente implementa la interfaz PicoAdviserOwner

significa que posee su propio Anunciante capaz de

notificar eventos acerca de su ciclo de vida.. Así, el

contenedor utilizará este anunciante para notificaciones.

Si no, el contenedor crea una instancia del Anunciante

por defecto PicoDefaultAdviser (ver Figura 7) y lo asigna

al componente.

Después de cada paso en el ciclo de vida del

componente el contenedor utiliza el Anunciante de ese

componente y llama al método correspondiente, que

creará un evento y lo mandará al Administrador de

Eventos para que sea reenviado a los oyentes.

Referencias[1] Apache Avalon framework. http://avalon.apache.org

[2] E Gamma, R. Helm, R. Johnson, J. Vissides. Design PatternsAddison-Wesley, 1995. ISBN: 0201633612

[3] JavaTM 2 Platform, Standard Edition, v 1.4.2, APISpecification http://java.sun.com/j2se/1.4.2/docs/api/

[4] Java/J2EE Spring frameworkhttp://www.springframework.org

[5] NanoContainer http://nanocontainer.codehaus.org

[6] PicoContainer http://picontainer.codehaus.org.

[7] Trygve Reenskaug, The original MVC.http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html.

package jhii;

public interface PicoComponentAdviser extends Adviser {

public void componentStarted();

public void componentStopped();

public void componentDisposed();

}

Figura 6 PicoComponentAdviser interface

package jhii;

public class PicoDefaultAdviser extends AdviserDefaultImplimplements PicoComponentAdviser {

public void componentStarted(){

if(component != null)

advise(new ComponentStartedEvent(component));

else

advise(new ComponentStartedEvent(this));

}

public void componentStopped(){

if(component != null)

advise(new ComponentStoppedEvent(component));

else

advise(new ComponentStoppedEvent(this));

}

public void componentDisposed(){

if(component != null)

advise(new ComponentDisposedEvent(component));

else

advise(new ComponentDisposedEvent(this));

}

}

Figura 7 PicoDefaultAdviser interface

Actas del II congreso javaHispano

77

Page 78: Actas del II congreso javaHispano

Actas del II congreso javaHispano

78

Page 79: Actas del II congreso javaHispano

Seguridad no intrusiva con Acegi Security System for Spring

Carlos Sánchez González Softgal

Plgno. POCOMACO, parcela I, nave 19, 15190 A Coruña - España

[email protected]

Abstract

Uno de los aspectos que toda aplicación debe considerar es

la seguridad, entendiendo como tal la necesidad de saber

que el usuario es quien dice ser (autenticación), y permitirle

acceso sólo a aquellos recursos necesarios (autorización).

Acegi Security System for Spring proporciona la

funcionalidad necesaria para adoptar mecanismos de

seguridad en aplicaciones Java utilizando características de

programación orientada a aspectos, de forma transparente

para el desarrollador, sin necesidad de desarrollar código,

utilizando para ello el soporte prestado por el framework

Spring, pero siendo posible utilizarlo en aplicaciones no

desarrolladas con Spring. En este artículo se detallarán las

funcionalidades que ofrece y una visión detallada sobre la

arquitectura del sistema, así como un simple ejemplo que

demostrará la sencillez con la que se puede adoptar su uso.

Keywords: Acegi, Spring Framework, seguridad, autenticación, autorización, java.

1 Introducción

Aplicar una política de seguridad a una aplicación es un

aspecto que afecta a prácticamente la totalidad de las

aplicaciones empresariales, y si no se adopta desde una

perspectiva correcta puede llegar a ser una carga que

afectará y lastrará el desarrollo del sistema.

Si bien existe el estándar JAAS (Java Authorization and

Authentication Service) que pretende cubrir tanto

autenticación como autorización, su adopción dista

mucho de ser sencilla y portable, debido a que el soporte

proporcionado por los contenedores de aplicaciones

dista mucho de ser adecuado, existen incompatibilidades

entre distintas implementaciones y cada contenedor

requiere una configuración distinta, normalmente con

adición de librerías. Por otro lado la funcionalidad

proporcionada por Acegi es mucho mayor, y además

permite la integración con JAAS, utilizándolo en la fase

de autenticación.

Acegi Security System [1] es un framework creado por

Ben Alex e íntimamente ligado al proyecto Spring [2], si

bien no requiere su utilización en nuestra aplicación, que

facilita la tarea de adoptar medidas de seguridad en

aplicaciones Java, sean aplicaciones standalone o

aplicaciones web. Y lo mejor de todo es que es open

source, sin coste de licencias y con la seguridad añadida

que proporciona el respaldo de un enorme y creciente

grupo de usuarios que lo están utilizando, y con un

manual de referencia con más de 50 páginas que no

tiene nada que envidiar a la documentación de un

producto comercial.

La arquitectura de Acegi está fuertemente basada en

interfaces y en patrones de diseño, proporcionando las

implementaciones más comúnmente utilizadas y

numerosos puntos de extensión donde nuevas

funcionalidades pueden ser añadidas. Esta arquitectura

puede hacer un poco difícil seguir el flujo de ejecución al

principio, pero una vez comprendida la idea global se

acepta como el precio necesario para poder disfrutar de

un framework con una gran potencia.

Como ejemplo se mostrará la configuración realizada en

el proyecto ONess [3] para la protección de peticiones

http en una aplicación web, además de mencionar uno

de los completos ejemplos que se distribuyen con el

proyecto.

1 Autenticación

Antes de poder tomar decisiones sobre si un usuario

puede acceder o no a un recurso, el usuario debe

identificarse para comprobar su identidad. Para ello

Actas del II congreso javaHispano

79

Page 80: Actas del II congreso javaHispano

existe el interfaz Authentication, desde el que se puede

acceder a tres objetos:

• principal, típicamente un nombre de usuario.

• credentials, las credenciales del usuario que

prueban que es quien dice ser, normalmente su

contraseña, aunque podría ser otro tipo de

información como certificados electrónicos.

• authorities, un lista de los roles que posee el

usuario o grupos a los que pertenece.

Cuando el usuario se autentica se crea un objeto

Authentication, con los dos primeros objetos, principal y

credenciales. En el caso de autenticación mediante

nombre de usuario y contraseña se creará un objeto

UsernamePasswordAuthenticationToken.

Acegi proporciona las clases necesarias para que esta

autenticación se realice mediante usuario y contraseña,

utilizando un adaptador para enlazar con la

autenticación proporcionada por un contenedor de

aplicaciones como son catalina, jboss, resin o jetty, o

utilizando el servicio de Single Sign On que proporciona

el proyecto CAS de la universidad de Yale [4].

Una vez creado este objeto Authentication se pasa al

AuthenticationManager, que a partir del principal y las

credenciales determina si éstas concuerdan con las

esperadas, añadiéndole al objeto Authentication las

authorities correspondientes en caso afirmativo o

lanzando una excepción de tipo AuthenticationException

en caso contrario.

Acegi proporciona una implementación del gestor de

autenticación AuthenticationManager que debería ser

suficiente para la mayoría de los casos, el

ProviderManager. Esta clase tan sólo delega la

autenticación en una lista de proveedores configurable,

cada uno de los cuales implementa el interfaz

AuthenticationProvider. Entre las implementaciones de

proveedores suministradas con el proyecto se

encuentran las necesarias para realizar la autenticación

contra varios servidores de aplicaciones (catalina, jboss,

resin y jetty), contra un fichero de configuración JAAS,

contra CAS (la solución Single Sign On de la universidad

de Yale [4]), y contra un objeto de acceso a datos

usando DaoAuthenticationProvider, que es el

comúnmente usado puesto que es el que permite

acceder a la información almacenada en una base de

datos.

El proveedor DaoAuthenticationProvider merece una

mención especial. Esta implementación delega a su vez

en un objeto de tipo AuthenticationDao, un interfaz que

define un objeto de acceso a datos con un único método

loadUserByUsername que permite obtener la

información de un usuario a partir de su nombre de

usuario. Acegi proporciona dos implementaciones de

este interfaz, InMemoryDaoImpl, en la que la

información de los usuarios se guarda en memoria, útil

para la realización de pruebas, y JdbcDaoImpl, que

accede a una base de datos a través de JDBC. Realizar

implementaciones de este interfaz es sumamente sencillo

y en el proyecto ONess [3] se encuentra disponible una

implementación que utiliza el mapeador objeto-

relacional Hibernate.

Entre otras características que también se proporcionan

de forma transparente, tan sólo estableciendo unos

parámetros de configuración, son soporte para cifrado

de contraseñas (SHA y MD5), caché de la información de

autenticación y redirección automática de peticiones

http a canales seguros https para aquellas urls que

deseemos.

Para el caso de aplicaciones web existen tres formas de

que un usuario se autentique:

• Utilizando autenticación de tipo BASIC, definida

en el RFC 1945, el usuario introduce su usuario

y contraseña en una simple ventana emergente

del navegador. Es necesario en el caso de que se

quieran añadir características de seguridad a

servicios web.

• Autenticándose mediante un formulario web, es

la forma más habitual ya que permite integrar el

formulario de login en la aplicación web.

• Utilizando el servicio de autenticación central

CAS de la Universidad de Yale [4], en caso de

que se requieran características de Single Sign

On, de forma que el usuario sólo tiene que

autenticarse una vez para todos los servicios

que puedan proporcionarse en el ámbito de una

empresa, incluso en distintos servidores y

desarrollados con distintos lenguajes de

programación.

Cada una de las formas anteriores requiere de la

configuración del filtro correspondiente en el descriptor

de aplicación web, BasicProcessingFilter,

AuthenticationProcessingFilter o CasProcessingFilter

respectivamente. La forma de configurarlos es definir los

Actas del II congreso javaHispano

80

Page 81: Actas del II congreso javaHispano

filtros como del tipo FilterToBeanProxy, delegando,

según un parámetro de inicialización, en uno de los

filtros anteriores definidos en el contexto de aplicación

de Spring, lugar donde pueden ser más fácilmente

configurados.

Los clientes llamados “ricos” o aplicaciones standalone

también están soportados, utilizando un gestor de

autenticación remoto cuya implementación utiliza un

servicio web en el lado del servidor, utilizando

RemoteAuthenticationManager y

RemoteAuthenticationProvider.

2 Autorización

Una vez el usuario está autenticado entra en juego la

parte del sistema encargada de la autorización, con el fin

de permitir que el usuario acceda sólo a aquellos

recursos a los que tiene permiso. Para ello Acegi

intercepta las llamadas a los objetos, utilizando proxies

dinámicos u orientación a aspectos basada en AspectJ, o

las peticiones http, utilizando filtros, y actúa en

consecuencia. Así permite restringir tanto llamadas a

métodos de determinadas clases o instancias, así como

acceso a urls.

Cuando se intercepta una petición a un recurso

protegido se comienza una cadena de eventos que

finalizará permitiendo el acceso al recurso o lanzando

una excepción AccessDeniedException. La cadena

comienza en un objeto de tipo AccessDecisionManager,

que a partir del objeto Authentication y de los

parámetros de configuración decide si la llamada debe

proseguir. Acegi proporciona tres implementaciones de

AccessDecisionManager que se basan en el concepto de

una votación, pero diferenciando las reglas de decisión:

• UnanimousBased: permite el acceso si no hay

votos negativos

• AffirmativeBased: permite el acceso si un voto

es afirmativo

• ConsensusBased: permite el acceso si el número

de votos positivos es mayor o igual que el de

negativos

Al igual que en la autenticación el ProviderManager

delegaba en una lista de AuthenticationProviders, en el

caso de la autorización el AccessDecisionManager delega

la facultad de emitir votos en objetos de tipo

AccessDecisionVoter. Se proporcionan dos

implementaciones de éste último interfaz:

• RoleVoter, que comprueba que el usuario

presente un determinado rol, comprobando si

se encuentra entre sus authorities.

• BasicAclEntryVoter, que a su vez delega en una

jerarquía de objetos que permite comprobar si

el usuario supera las reglas establecidas como

listas de control de acceso.

El primer caso es el más común, proporcionando una

autenticación basada en grupos o roles, donde se

permite el acceso si el usuario pertenece a alguno de los

configurados como requeridos. En el segundo caso se

permite restringir el acceso a objetos a nivel de instancia,

caso que será discutido más adelante.

En ambos casos el sistema que intercepta las llamadas

debe ser configurado. En el caso de las aplicaciones web

se hará mediante la configuración de un filtro en el

fichero web.xml.

Los posibles recursos que se pueden proteger son

• urls, mediante un filtro en el descriptor de

aplicación web, FilterSecurityInterceptor.

• métodos de objetos definidos en el contexto de

aplicación de Spring, utilizando

MethodSecurityInterceptor.

• cualquier PointCut definible en AspectJ,

mediante AspectJSecurityInterceptor.

2 Autorización a nivel de instancia mediante listas de control de acceso

Existen casos en los que la protección de las llamadas a

métodos no es suficiente, necesitando protegerse de

distinta forma distintas instancias de una clase. Como

ejemplo se puede pensar en un sistema de ficheros, en

los que cada archivo tiene distintos permisos, según si el

usuario que accede a ellos es el dueño del archivo,

pertenece al grupo del dueño o no cumple ninguna de

las opciones anteriores.

Acegi proporciona en sus últimas versiones el soporte

necesario para implementar seguridad basada en listas

de control de acceso. Las clases clave que se deben

conocer son

• BasicAclEntryVoter obtiene las ACLs del objeto

llamado y vota sobre si se debe permitir el

acceso a él o no.

Actas del II congreso javaHispano

81

Page 82: Actas del II congreso javaHispano

• BasicAclAfterInvocationProvider permite

denegar el acceso a un objeto después de que

el método se haya invocado, útil cuando no se

puede saber a priori.

• BasicAclAfterInvocationollectionFilteringProvider

, similar al anterior, elimina los objetos a los que

el acceso no ha sido permitido en aquellos

métodos que devuelven colecciones.

Para más detalles sobre ACLs se recomienda consultar el

completo manual de referencia de Acegi.

2 Ejemplo

Como ejemplo se utilizará el proyecto ONess [3],

subproyectos user-model y user-webapp. En este

proyecto se ha configurado una aplicación web para

proteger sus recursos en peticiones http. Se han omitido

partes no relevantes para este ejemplo, pero que pueden

ser consultadas en la página web y en el repositorio de

código fuente del proyecto, entre otros la configuración

necesaria para utilizar autenticación basada en HTTP

BASIC o CAS o las clases necesarias para ejecutarlo.

Acegi utiliza el contexto de aplicación de Spring para

definir la configuración necesaria. Para aquellas personas

que no están familiarizados con Spring decir que tan

sólo es necesario crear un fichero /WEB-

INF/applicationContext.xml con el contenido que se

muestra en la Fig. 1 y añadir a /WEB-INF/web.xml el

contenido de la Fig. 2. En este segundo fichero se

configura un listener que procesa el primero

automáticamente cada vez que el contenedor de

aplicaciones inicia la aplicación web, y unos filtros que

procesan todas las peticiones que llegan.

La autenticación se realiza a través de un objeto de

acceso a datos DAO implementado con el mapeador

objeto-relacional Hibernate, authenticationDao, para

acceder a la información de usuarios almacenada en una

base de datos. Como alternativa para realizar pruebas

también se incluye comentada la definición de un DAO

de tipo InMemoryDaoImpl. Como proveedor de

autenticación se utiliza por tanto

DaoAuthenticationProvider, configurándose con una

caché de usuarios basada en EHCache. Por comodidad

no se ha activado el cifrado de contraseñas, acción que

puede realizarse con tan sólo descomentar la línea

indicada. El gestor de autenticación ProviderManager

tan sólo tendrá como proveedor el anteriormente

mencionado, ya que el único repositorio de usuarios será

la base de datos.

En la aplicación web es necesario añadir dos filtros,

Acegi Security System for Spring Http Session Integration

Filter, que hace que la información de autenticación esté

disponible para sucesivas peticiones del usuario al

guardarla en la sesión, y Acegi Authentication Processing

Filter para procesar el formulario de login de un usuario.

El primer filtro no requiere configuración, mientras que

el segundo la delega en el contexto de aplicación de

Spring, definiendo un bean

authenticationProcessingFilter, donde se referencia el

gestor de autenticación anteriormente configurado y la

página a la que ir en caso de error en el login, entre

otros, y authenticationProcessingFilterEntryPoint, donde

se configura la página donde se encuentra el formulario

de login.

En cuanto a autorización, las decisiones se tomarán

basándose en los roles del usuario utilizando RoleVoter,

y puesto que tan sólo existe ese AccessDecisionVoter no

influirá el gestor de decisiones, optando por un

AffirmativeBased.

En la aplicación web se configurará un filtro Acegi HTTP

Request Security Filter para restringir el acceso a

determinadas urls. Este filtro al igual que los anteriores

se configura mediante el contexto de aplicación de

Spring, donde se define un FilterSecurityInterceptor,

filterInvocationInterceptor, que define los roles

necesarios para acceder a las urls utilizando comodines,

y se define también securityEnforcementFilter, donde se

enlazan el interceptor, para el caso en el que el usuario

ya está autenticado, y el punto de entrada, para el caso

contrario.

<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- AUTENTICACION --> <!-- Data access object which stores authentication information -->

Actas del II congreso javaHispano

82

Page 83: Actas del II congreso javaHispano

<!-- Hibernate implementation --> <bean id="authenticationDao" class="net.sf.oness.user.model.dao.UserHibernateDao"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <!-- Implementacion util para pruebas <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl"> <property name="userMap"> <value> marissa=koala,ROLE_USER,ROLE_ADMIN dianne=emu,ROLE_USER scott=wombat,ROLE_USER peter=opal,disabled,ROLE_USER </value> </property> </bean> --> <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="authenticationDao"><ref local="authenticationDao"/></property> <property name="userCache"><ref local="userCache"/></property> <!-- Descomentar para activar cifrado de contraseñas <property name="passwordEncoder"><ref local="passwordEncoder"/></property> --> </bean> <bean id="passwordEncoder" class="net.sf.acegisecurity.providers.encoding.Md5PasswordEncoder"/> <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"> <property name="minutesToIdle"><value>5</value></property> </bean> <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref local="daoAuthenticationProvider"/> </list> </property> </bean> <!-- Filtro web --> <bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager"> <ref bean="authenticationManager"/> </property> <property name="authenticationFailureUrl"> <value><![CDATA[/show.do?page=.login&login_error=1]]></value> </property> <property name="defaultTargetUrl"><value>/</value></property> <property name="filterProcessesUrl"><value>/security_check</value></property> </bean> <bean id="authenticationProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl"> <value><![CDATA[/show.do?page=.login]]></value> </property> <property name="forceHttps"><value>false</value></property>

Actas del II congreso javaHispano

83

Page 84: Actas del II congreso javaHispano

</bean> <!-- AUTORIZACION --> <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/> <bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased"> <property name="allowIfAllAbstainDecisions"><value>false</value></property> <property name="decisionVoters"> <list> <ref local="roleVoter"/> </list> </property> </bean> <!-- Filtro web --> <bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter"> <property name="filterSecurityInterceptor"> <ref bean="filterInvocationInterceptor"/> </property> <property name="authenticationEntryPoint"> <ref local="authenticationProcessingFilterEntryPoint"/> </property> </bean> <bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager"> <ref bean="authenticationManager"/> </property> <property name="accessDecisionManager"> <ref bean="accessDecisionManager"/> </property> <property name="objectDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /secure/**=ROLE_ADMIN /**/*create*=ROLE_USER,ROLE_ADMIN /**/*edit*=ROLE_USER,ROLE_ADMIN /**/*update*=ROLE_USER,ROLE_ADMIN /**/*delete*=ROLE_USER,ROLE_ADMIN </value> </property> </bean> </beans> Figura 1. Spring application context

<!-- carga el contexto de aplicación de /WEB-INF/applicationContext.xml --> <listener> <listener-class>net.sf.oness.common.webapp.controller.listener.SpringContextLoaderListener</listener-class> </listener> <filter> <filter> <filter-name>Acegi Security System for Spring Http Session Integration Filter</filter-name> <filter-class>net.sf.acegisecurity.ui.HttpSessionIntegrationFilter</filter-class> </filter> <filter-name>Acegi Authentication Processing Filter</filter-name> <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>

Actas del II congreso javaHispano

84

Page 85: Actas del II congreso javaHispano

<init-param> <param-name>targetClass</param-name> <param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value> </init-param> </filter> <filter> <filter-name>Acegi HTTP Request Security Filter</filter-name> <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class> <init-param> <param-name>targetClass</param-name> <param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi Security System for Spring Http Session Integration Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Acegi Authentication Processing Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Acegi HTTP Request Security Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Figura 2. web.xml

Otro completísimo ejemplo “contacts” puede

encontrarse en la distribución de Acegi Security,

incluyendo autorización basada en listas de control de

acceso, y acceso remoto desde aplicaciones standalone.

8 Conclusiones

Acegi es uno de los mejores frameworks de seguridad

existentes en Java, potente y flexible a la vez que sencillo

de configurar, sin necesitad de modificar código ya

existente y portable entre distintos contenedores de

aplicaciones sin necesidad de cambios. Su integración

con Spring hace que sea el recomendado para añadir

funcionalidades de seguridad a las aplicaciones que

utilizan ese magnífico framework, cuyo número crece día

a día, si bien puede ser utilizado en cualquier tipo de

aplicación sin ningún problema.

En este artículo se dado una visión global del framework

y se ha mostrado con un ejemplo cómo se pueden

proteger las urls de una aplicación web sin necesidad de

modificar ni una línea de código. Para mayor

información se recomienda la lectura del manual de

referencia, realmente completo.

Agradecimientos

A Ben Alex, principal desarrollador del proyecto Acegi,

por su colaboración.

Referencias

[1] Acegi Security System for Spring http://acegisecurity.sourceforge.net.

[2] Spring Framework http://www.springframework.org.

[3] ONess http://oness.sourceforge.net

[4] CAS (Central Authentication Service). Universidad de Yale, http://www.yale.edu/tp/auth/.

[5] Weblog del autor http://www.jroller.com/page/carlossg

Actas del II congreso javaHispano

85

Page 86: Actas del II congreso javaHispano

Actas del II congreso javaHispano

86

Page 87: Actas del II congreso javaHispano

Estándares libre y Java: ¿Es el JCP un organismo que crea estándares libres?

Abraham Otero Quintana Dep. de Electrónica y Computación. Edificio Monte da Condesa.

Santiago de Compostela, 15768. España [email protected]

Abstract

La plataforma Java ha sido y es blanco de las críticas de

numerosos activistas de la comunidad del Software

Libre (SL) por “no ser Software Libre”. Sin embargo

Java, a diferencia de otras alternativas, no es un

software, sino un conjunto de especificaciones que

definen una serie de tecnologías. Por ello carece de

sentido juzgar si la plataforma Java es o no libre en base

a la licencia de algunas de las implementaciones de un

subconjunto de las especificaciones, principal base de

las críticas de la comunidad del SL. Lo que deberíamos

plantearnos, dada su condición de especificaciones, es si

Java puede considerarse o no un estándar libre.

En este trabajo analizaremos el proceso de creación de

las especificaciones de la plataforma Java para

determinar si Java es o no libre. Emplearemos en este

análisis tanto los criterios de la comunidad del SL,

creados bajo la dirección de Bruce Perens, como los

criterios de la comunidad académica. También se

discutirá la problemática relacionada con la licencia de

las implementaciones de referencia de la plataforma y

se propondrá una solución que busca un equilibrio entre

los intereses de la comunidad del SL y de Sun

Microsystems.

Keywords: Libertad de Java, estándares libres, Java Community Process, Software Libre.

1 Introducción

Determinar la libertad de la plataforma Java no es

cuestión de analizar las licencias bajo las que se

distribuye el conjunto de herramientas de desarrollo

(JDK), o el entorno de ejecución (JRE) de Sun

Microsystems, principal fuente de críticas de la

comunidad del SL hacia Java. La plataforma Java no

es un software concreto, sino un conjunto de

especificaciones que definen todas y cada una de las

tecnologías que componen la plataforma. Un análisis

acerca de la libertad de la plataforma no puede

basarse en la licencia de una, o varias, de las

implementaciones de un subconjunto de estas

especificaciones, que es en lo que habitualmente la

comunidad del SL basa sus críticas, sino que debe

analizar el proceso de creación y mantenimiento de

las especificaciones que definen la plataforma Java.

Esta tarea, creación y mantenimiento de las

especificaciones, es responsabilidad de un organismo,

el Java Community Process (JCP) [1], cuya

organización y funcionamiento básico se perfilará en

este trabajo. A continuación se estudiará si las

especificaciones creadas por el JCP pueden o no

considerarse estándares libres. Para ello se tendrán en

cuenta tanto los criterios de la comunidad del SL,

creados bajo la dirección de Bruce Perens, como los

criterios de la comunidad académica, definidos por

Ken Krechmer. Irónicamente Java cumple con creces

los primeros, pero falla en los segundos.

Finalmente, y dado que la licencia de las

implementaciones de referencia (IR) parece ser tan

importante para el moviendo del SL, se discute este

problema. Se mostrará que el miedo a la

fragmentación con el que Sun se excusa para no

liberar su código es infundado. Sun defiende que las

ideas del movimiento del SL, acceder y modificar el

código fuente del software sin restricciones, entran

en conflicto con el principio básico de la plataforma

Java: “escríbelo una vez y ejecútalo en cualquier sitio”

(adaptación de “Write Once Run Anywhere”, WORA).

Se mostrará que en la práctica no hay evidencias de

que esta fragmentación pudiera producirse y se

propondrá una fórmula mediante la cual Sun podría

seguir manteniendo el control de Java a nivel

Actas del II congreso javaHispano

87

Page 88: Actas del II congreso javaHispano

empresarial y cobrando royalties por estas tecnologías

(dos ventajas relevantes de Sun sobre sus

competidores empresariales), a la vez que libera el

código de las IR.

2 ¿Qué es la plataforma Java?

Hill Venners en su libro Inside the Virtual Machine [2]

afirma que Java está formado por cuatro piezas

diferentes: una especificación de un lenguaje de

programación; una especificación de un formato

binario, los bytecodes; una especificación de una

máquina virtual, encargada de interpretar los

bytecodes; y un conjunto de librerías estándar. Sin

duda estos cuatro elementos definen el lenguaje de

programación Java.

Sin embargo, si Java ha alcanzado tanto éxito y

difusión no es sólo gracias al lenguaje, sino también

al resto de la plataforma, que integra múltiples

tecnologías en su seno: tecnologías para el desarrollo

de aplicaciones Web (Servlets, JSP, portlets, etc.),

aplicaciones empresariales (EJB, JTA, JCA, JMS, etc.),

aplicaciones para telefonía móvil (CLCD, CDC, OpenGL

ES, etc.), tarjetas inteligentes (JavaCard), y un

inmenso sinfín de tecnologías que hicieron a Java

único hasta hace tan sólo un par de años, cuando

apareció .NET.

El fin de este trabajo no es sólo analizar la libertad del

lenguaje de programación, y/o del JDK distribuido por

Sun, sino de toda la plataforma en su conjunto. Por

ello, para nuestros objetivos, es más correcto

considerar que la plataforma Java está compuesta por

un conjunto de especificaciones, que definen todas y

cada una de las partes de la plataforma, y una serie

de implementaciones de estas especificaciones. Sin

duda, por ser la base sobre la cual se edifica el resto

de la plataforma, las especificaciones del lenguaje,

bytecode, máquina virtual, y de las librerías estándar

juegan un papel protagonista, pero no son las únicas.

3 El Java Community Process

El Java Community Process [1] es el organismo que

dirige, mediante la creación de nuevas

especificaciones y el mantenimiento de las ya

existentes, la evolución plataforma Java. El JCP define

su propio funcionamiento y las normas por las que se

rige, normas que han ido evolucionando desde su

creación en Diciembre de 1998. La versión actual del

JCP, y la que se describe en este documento, es la 2.6

[3].

El JCP es administrado por el Program Management

Office (PMO), organismo formado por asalariados de

Sun Microsystems. Dos Comités Ejecutivos (CE) se

encargan de aprobar las modificaciones y extensiones

de la plataforma; uno encargado de las

especificaciones relacionadas con J2EE y J2SE

(ediciones empresarial y estándar, respectivamente,

de la plataforma), y el otro de las relacionadas con

J2ME (edición para pequeños dispositivos: teléfonos

móviles, tarjetas inteligentes…). Cada uno de estos

comités está compuesto por 16 miembros con

derecho a voto, 5 elegidos mediante votación entre

los miembros del JCP, votación en la que participan

todos los miembros del JCP. 10 son propuestos por el

PMO, siguiendo los criterios de “comunidad

balanceada” y “representación regional” [3]. Estos

miembros han de ser ratificados mediante votación

pública. El miembro restante es un representante de

Sun. En cada comité hay un segundo representante

de Sun, que ejerce la labor de presidente, pero que

no posee derecho a voto.

Convertirse en miembro del JCP es gratis para

empresas licenciatarias de Sun (empresas que

implementan especificaciones de la plataforma con

ánimo de lucro y pagan por ello a Sun), y para

personas que a título individual deseen formar parte

del JCP. Las empresas no licenciatarias han de pagar

5000 $ por año. En el caso de organizaciones sin

ánimo de lucro e instituciones académicas es un

comité formado por un miembro de Sun, un miembro

del mundo del SL o del mundo académico,

Actas del II congreso javaHispano

88

Page 89: Actas del II congreso javaHispano

Figura 1 Diversas etapas por las que pasa un Java Specification Request.

y un miembro elegido democráticamente, quien decide

si pueden formar parte del JCP gratis, o han de pagar

2000 $.

Las incorporaciones de nuevas tecnologías a la

plataforma Java se realizan a través del JCP, mediante un

“Java Specification Request” [4] (JSR). Para crear un JSR

se ha de explicar en un documento la necesidad de la

nueva tecnología, o de modificación de una tecnología

ya existente, y cómo afectará este cambio al resto de la

plataforma. Aunque no es necesario, también es

recomendable proponer un grupo de expertos que se

encargará de desarrollar el JSR, en caso de ser aceptado.

Cualquiera, sea o no miembro del JCP, puede proponer

nuevos JSR. Uno de los dos CE del JCP, según el nuevo

JSR afecte a J2ME o a J2SE/J2EE, analiza la propuesta y

decide si acepta o no la creación del JSR. Esta decisión se

realiza mediante una votación pública, donde el nuevo

JSR debe obtener mayoría simple.

A continuación el grupo de expertos, normalmente

liderados por quien propuso el nuevo JSR, trabaja sobre

la especificación. Deberán completar el documento que

define la nueva tecnología o modificación de una ya

existente, una implementación que prueba que la

tecnología es factible, denominada Implementación de

Referencia (IR), y un Test de Compatibilidad (TC), una

batería de pruebas que permite comprobar si una

implementación cumple o no con la especificación.

Tanto la IR como el TC son desarrollados bajo la licencia

que el líder del grupo de expertos decida, pudiendo

optar por cualquier licencia libre.

En una primera fase el grupo de expertos se centra en la

definición la tecnología. Primero debe crear un borrador

de la especificación, “Early Draft”, que se publica en

Internet y es accesible a todo el mundo; cualquier

individuo con o sin vinculación con el JCP puede

estudiar, opinar y enviar realimentación sobre este

borrador al grupo de expertos. En base a la

realimentación de la comunidad el grupo de expertos

realiza modificaciones, completa la especificación y

nuevamente hace pública una versión más madura de la

especificación, el “Public Draft”. Nuevamente cualquiera

puede enviar realimentación a cerca de este documento,

y el grupo de expertos puede realizar cambios en base a

la realimentación.

Cuando se llega a un acuerdo en la especificación ésta

ha de ser ratificada por el CE correspondiente, mediante

votación pública en la que necesita una mayoría simple

de los votos emitidos. Si es ratificada pasa a una tercera

fase, donde es toda la comunidad la que revisa y

comenta la especificación, mientras que el líder del

grupo de expertos se encarga del desarrollo de la IR y el

TC. Una vez que el grupo de expertos ha terminado su

trabajo éste, nuevamente, ha de ser aprobado por el CE

correspondiente mediante una votación pública.

Finalmente se entra en una fase cíclica de

mantenimiento de la tecnología, fase también abierta al

público (ver Fig. 1).

Hay una serie de JSR en los que Sun tiene privilegios

especiales y que se rigen por unas normas ligeramente

diferentes: los “Umbrella Java Specification Request”

(UJSR) [3]. Estos son los JSR que definen las tres

ediciones de la plataforma: J2SE, J2EE, J2ME y los

diversos perfiles de J2ME. Estos JSR “paraguas”

protegen, entre otros, la especificación de la máquina

virtual, el lenguaje, y el bytecode. Los cambios en estas

especificaciones pueden afectar a la compatibilidad hacia

atrás, o a la portabilidad, de las aplicaciones, por ello

Sun justifica este trato especial. Cualquier nueva

Actas del II congreso javaHispano

89

Page 90: Actas del II congreso javaHispano

funcionalidad o tecnología que quiera incorporarse a

cualquiera de las tres ediciones de la plataforma ha de

hacerlo a través de un UJSR.

Para que un UJSR sea aprobado debe obtener al menos 5

votos positivos del CE correspondiente, y de los votos

emitidos al menos dos tercios han de ser de aprobación.

Además el representante de Sun puede vetar la nueva

especificación, lo que se traduce en que Sun tiene la

última palabra en lo que se refiere a la aprobación de los

UJSR, y por lo tanto a cambios sobre J2SE, J2EE y J2ME.

No todos los JSR se rigen por las normas aquí descritas;

como ya se ha comentado el propio JCP es un JSR que

evoluciona y por lo tanto sus normas cambian. En un

principio no era tan abierto, no permitiendo, por

ejemplo, la implementación de los TC e IR bajo licencias

libres. Sun también tenía derechos de veto sobre más

JSR, y las implementaciones de las especificaciones

estaban obligadas a respetar las posibles patentes que

hubiese en las especificaciones, obligación que ya no

existe en la actualidad. Algunos JSR todavía se guían por

versiones anteriores del JCP, siendo el líder del grupo de

expertos el que puede actualizar, si lo considera

conveniente, la versión del JCP. Es de esperar que según

estos JSR saquen nuevas versiones de mantenimiento se

vayan pasando a la última versión del JCP, más abierta y

más respetuosa con el mundo del SL.

Finalmente, cualquiera puede implementar las

especificaciones, y distribuir su implementación bajo la

licencia que considere oportuno. No está obligado a

pasar el TC, pero si desea hacerlo (esto es imprescindible

si se desea emplear la marca registrada “Java” y términos

relacionados), y ha realizado la implementación con

ánimo de lucro, ha de pagar a Sun por pasar el TC. Si la

implementación ha sido realizada por una organización

sin ánimo lucro, como suele ser el caso de los desarrollos

libres, el mismo comité de tres personas que decide si las

organizaciones sin ánimo de lucro pagan por pertenecer

al JCP, decide si ha de pagar o no por pasar el TC. No

pasar el TC no implica que una determinada

implementación no cumpla la especificación, sin

embargo es una garantía para sus usuarios de que

efectivamente la cumple.

3.1 Estándares vs especificaciones

El nombre que recibe la documentación que define las

tecnologías que forman la plataforma Java es

“especificaciones”; sin embargo cuando se habla de

libertad, tanto dentro del mundo del SL como en el

académico, se emplea el término “estándares”. Cabe

preguntarse qué diferencias hay entre una especificación

y un estándar; y si podemos juzgar a las especificaciones

de la plataforma Java con los criterios de los estándares

libres. He aquí una definición de cada uno de estos

términos:

• Un estándar es una tecnología, formato o método

desarrollado y adoptado a través de un proceso

abierto de consenso, bajo la guía de cuerpos

nacionales (ANSI, BSI, ect.) o internacionales (ISO,

IEEE, etc.) de estándares.

• Una especificación es un conjunto de documentos

desarrollados por un grupo dentro de la industria,

pero sin guías o procedimientos formales que

aseguren que el trabajo está abierto a cualquier otra

parte interesada, o abierto para su revisión y

comentario durante el desarrollo (IETF, WC3, OMG,

etc.).

En algunas definiciones, como la aquí recogida, se exige

que un estándar esté aprobado por un organismo

reconocido oficialmente, un SDO (Standard Definition

Organization), mientras que en otras no se especifica el

tipo de organismo que debe reconocerlo. En otras

ocasiones sólo se le requiere que “esté creado a través

de un procedimiento abierto que garantice que se

escucharán toda las partes interesadas y se llegará a un

consenso”.

Las especificaciones del JCP se definen entre más de 700

organizaciones e individuos, entre la cuales se hallan

todas las grandes empresas de informática menos

Microsof; están abiertas a todo el que las quiera

examinar; cualquiera puede participar gratuitamente en

el JCP, y por lo tanto en la definición y evolución de la

plataforma; e incluso sin pertenecer al JCP se puede

contribuir al proceso de definición de las

especificaciones. No parece justo caracterizar de

“especificación” (al menos en el sentido de cierta

bibliografía), a algo que es consensuado entre tantas

partes, con garantías de acceso, transparencia, y con

posibilidad de participación sin discriminación en su

construcción. Por otro lado en la bibliografía sobre

estándares libres se trata a las especificaciones del JCP

como “estándares” [5].

Evitaremos entrar más en discusiones lingüísticas y, dado

el carácter consensuado y abierto de las especificaciones

del JCP las trataremos como “estándares”, aún cuando

Actas del II congreso javaHispano

90

Page 91: Actas del II congreso javaHispano

no estén reconocidas por organismos de estándares

oficiales. El motivo principal para ello es la lentitud de la

evolución de los estándares en los organismos oficiales.

En su día Sun consideró llevar a ISO las especificaciones

del JCP, pero lo descartó porque ISO ralentizaría

demasiado la evolución de la plataforma: más de un

estándar definido dentro de ISO u organismos similares

se ha quedado obsoleto antes de llegar a ver la luz.

4 Importancia de los estándares libres

La interoperabilidad, capacidad de un sistema para

trabajar con otro, es una de las características más

deseables para cualquier aplicación informática. De poco

nos valdría un cliente de correo que no siga el protocolo

SMTP, un procesador de textos cuyos documentos sólo

se pudiesen visualizar y editar en la máquina donde se

crearon, o un servidor web que no respeta el protocolo

http. En el pasado era posible concebir un sistema

informático que no interoperaba con ningún otro

sistema; sin embargo en la era de Internet, donde

proliferan múltiples aplicaciones distribuidas que son

accedidas por múltiples dispositivos de diversa

naturaleza (PCs, PDA, terminales móviles de última

generación, mainframes…) no hay lugar para este tipo

de islas.

El software libre por sí sólo no genera interoperabilidad;

los estándares son la base para conseguirla. De aquí la

enorme importancia de contar con estándares libres,

para invitar que estándares propietarios coarten la

libertad del software, aún cuando su código fuente sea

libre. Los estándares propietarios, o el no uso de

estándares, es un mecanismo para entorpecer e incluso

anular el desarrollo de soluciones de terceros (en especial

las libres). Así por ejemplo los desarrolladores de

OpenOffice se ven obligados a hacer reingeniería inversa

para acceder a los formatos OLE de Microsoft, y se

exponen a ser demandados por sus actividades. De un

modo similar los desarrolladores de clientes de

mensajería libres que interactúan con la red MSN cada

vez que surge una nueva versión del protocolo MSNpX

deben reventarlo y actualizar los clientes; y Microsoft

podría cerrar la red de MSN, impidiendo que clientes de

terceros, libres y no libres, se conecten a su red.

Un estándar libre debe poder implementarse libremente.

Para ello su contenido ha de ser público y accesible,

eliminando las barreras de tipo técnico en la

implementación. Tampoco deben existir barreras de tipo

económico o legal (patentes y copyright) que impidan su

implementación; esto último es casi imprescindible para

el mundo del SL, que no puede permitirse pagar royalties

por usar el estándar, ni afrontar largos y costos juicios.

Un estándar libre respeta la libertad de elección:

podemos tomar hoy una decisión y mañana otra

diferente: si desarrollamos una web con ASP .NET nos

ataremos a un servidor web y a un sistema operativo. Si

empleamos JSP o php podremos cambiar en cualquier

momento de servidor web, ya que hay múltiples

vendedores e implementaciones libres que los soportan,

y/o de sistema operativo.

Incluso las más “pequeñas” estandarizaciones libres han

permitido enormes avances. Por ejemplo, fueron los

estándares libres como TCP/IP, FTP, HTML, SMTP, etc. los

que permitieron construir el único “caso de éxito”

auténtico en lo referente interoperabilidad: Internet. A

principios de los años 90 en las redes empresariales

coexistían un conjunto de protocolos propietarios para la

comunicación en red entre las máquinas de distintos

fabricantes (IBM, Apple, Microsoft, VAX, ect.) entre los

cuales era difícil interoperar. En este contexto Internet se

abre a las empresas y trae consigo TCP/IP, un protocolo

libre para la comunicación en red, y un conjunto de

protocolos libres para interoperar entre equipos (FTP,

Telnet, ect.). No le llevó mucho tiempo imponerse a los

otros protocolos propietarios siendo clave en su triunfo

la apertura del estándar, y el no tener que pagar ningún

tipo de royalties para emplearlo.

Un estándar libre fomenta la aparición de múltiples

implementaciones de características heterogéneas, libres

y comerciales. Esto beneficia al usuario final, ya que se

evita el “vendor lock-in”, quedar atrapado por un

proveedor del que dependo por haber basado mi

solución en su producto.

Tras estos argumentos cabe hacerse una pregunta:

¿Hasta que punto es “libre” un software cuyo código

fuente es libre pero que implementa un estándar

propietario? Podremos modificar su código fuente, pero

lo hacemos siempre dentro de la jaula (formato o

protocolo) que define el estándar propietario, que no

controlamos y al que estamos obligados a ceñirnos.

Podría darse el caso de que el dueño del estándar

propietario ponga trabas, o impida, el desarrollo del

producto libre. Un software “libre”, en el sentido más

general de la palabra, debe basarse en estándares libres.

Actas del II congreso javaHispano

91

Page 92: Actas del II congreso javaHispano

4.1 ¿Qué es un estándar libre?

Dentro de la comunidad del SL no hay una definición

globalmente aceptada sobre qué es un estándar libre.

Así, por ejemplo, ni Free Software Foundation (FSF) [6],

ni Open Source Iniciative (OSI) [7] proporcionan criterios

bien definidos para determinar si un estándar es o no

libre. El mayor esfuerzo en la definición de estos

criterios, dentro del mundo del Software Libre, está

liderado por Bruce Perens y desarrollado en el entorno

de Debian. Perens es uno de los principales líderes del

movimiento del SL, en el cual milita desde 1987;

cofundador de Open Source Iniciative es el autor del

manifiesto “Open Source Definition”. Actualmente hay

un borrador con el trabajo realizado hasta la fecha en

[8].

Otro trabajo interesante es el de Ken Krechmer, “The

Principles of Open Standards” [9]. Krechemer, a

diferencia de Pernes, no es un activista del Software

Libre. Su trabajo está orientado a organizaciones

sensiblemente diferentes del JCP, como ISO o ECMA, que

también estandarizan objetos materiales y tangibles, y

no sólo software, algo que se puede replicar y trasladar

de un punto a otro del planeta a coste prácticamente

cero. Por ello no todas las ideas que hay tras los criterios

de Krechemer poseen sentido en el mundo de lo

intangible. Sin embargo hay algunas ideas que sí

podemos tomar prestadas, ideas que no están presentes

entre las de Perens y que, desde el punto de vista de

autor, son de gran importancia en la definición de qué es

un estándar libre; dicho de otro modo: son carencias del

borrador de Perens.

Al margen de estos trabajos existen varios portales

dedicados a los estándares libres, pero ninguno de ellos

define de un modo concreto y preciso qué es un

estándar libre, y se hallan muy lejos de tener un peso

equivalente a que FSF u OSI tienen sobre el SL.

OpenStandards.org [10] es una web creada a principios

del 2000 con un propósito no muy claro y que en la

actualidad está abandonada, sin que nunca haya tenido

actividad real. OpenStandards.net [11] es un escaparate

de noticias de otros sitios web y un almacén de enlaces

que carece de contenidos propios. Mención a parte

merece Free Standards Group [12], dedicado a crear

estándares para el mundo Linux. Poseen certificaciones

de gran reconocimiento, como LSD (Linux Standard

Base), OpenI18n, OpenPrinting, etc. Sin embargo sus

interesantes objetivos, crear estándares para Linux, no

coinciden con los que se persiguen en este trabajo.

Los criterios sobre los que trabaja Perens constituyen el

intento más serio y consensuado de la comunidad del SL

para definir qué es un estándar libre, por ello los

emplearemos como base del análisis que realizaremos.

No obstante en este estudio añadiremos algunas ideas

del trabajo de Krechmer a los criterios de Perens, por

considerar que éstas los complementan.

5 ¿Está la plataforma Java compuesta por estándares libres?

En este apartado analizaremos el proceso de creación y

mantenimiento de los JSR así como las condiciones bajo

las cuales se puede acceder a ellos e implementarlos,

para determinar si Java puede o no considerarse un

estándar libre.

5.1 Criterios de Perens

El borrador creado por Pernees [8] en colaboración con

el entorno de Debian define una serie de requerimientos

que debe cumplir un estándar para considerase un

“estándar libre” (open standard). Además identifica una

serie de buenas prácticas, a modo de recomendaciones,

para los estándares libres, buenas prácticas que no se

exigen para poder considerarse como libre. Analizaremos

punto por punto cada uno de los requerimientos

descritos en este documento. En las siguientes

subsecciones el contenido en cursiva es un resumen, que

no una traducción, del contenido de cada uno de los

puntos del documento de Perens.

5.1.1 Disponibilidad:

Un estándar libre debe estar disponible para leer e

implementar por cualquier individuo u organización. Se

recomienda como buena práctica que la documentación

y la IR del estándar estén disponibles en Internet. No se

hace ninguna referencia a la licencia del código fuente

de la IR.

La documentación de cualquier JSR está disponible en

Internet, y cualquiera puede descargársela e

implementarlo. En cuanto a la IR de referencia de un JSR,

y su test de compatibilidad, son siempre accesibles de un

modo gratuito para un individuo u organización sin

ánimo de lucro.

Actas del II congreso javaHispano

92

Page 93: Actas del II congreso javaHispano

5.1.2 Maximizar la elección del usuario final

Los estándares abiertos deben generar un mercado

competitivo permitiendo un amplio rango de

implementaciones, con precios que varíen “desde muy

altos a nulos”.

Evitar el “vendor lock-in” es uno de los principios básicos

sobre los que se ha construido la plataforma, así como

una de sus principales ventajas frente a otras tecnologías

propietarias. En la práctica, efectivamente podemos

encontrar costosas implementaciones empresariales de

las especificaciones (Ej.: BEA WebLogic, IBM WebSphere

~100.000 $ por CPU) e implementaciones libres

completamente gratuitas (Ej.: JBoss, JOnAS, Gerónimo).

5.1.3 Sin Royalties:

Debe ser posible implementar una especificación sin

pagar royalties. Para garantizar que esto será siempre así

(evitar posibles patentes submarinas) cualquier patente

incluida en el estándar debe poderse implementar de un

modo totalmente libre de royalties. Perens acepta que la

certificación del estándar pueda requerir pagar, y

recomienda (aunque no exige) proporcionar un camino

para la auto-certificación.

Todas las patentes involucradas en un JSR deben

“garantizar una licencia perpetua, no excluyente,

mundial, sobre la cual nunca se podrá exigir ningún

pago (fully paid-up), libre de royalties e irrevocable” [13]

a quien las implemente.

La certificación de compatibilidad requiere pagar cuotas

a Sun, pero los TC son accesibles gratuitamente para

individuos y organizaciones sin ánimo de lucro [13], por

lo que es posible auto-certificarse. Además existe un

camino para la certificación gratuita de

implementaciones libres y sin ánimo de lucro: el servidor

de aplicaciones J2EE JOnAS se certificó completamente

gratis, y Geronimo lo hará en breve en las mismas

condiciones.

El código de la IR (y del TC) debe estar disponible bajo

condiciones RAND (Reasonable And Non Discriminatory)

[10], o más permisibles, para basar en ella otras

implementaciones. Como se discute en [5] las

condiciones RAND en la práctica pueden no ser

razonables y sí suelen ser discriminatorias; sin embargo

que el código esté disponible bajo condiciones no más

restrictivas que RAND es mejor que ningún tipo garantía.

5.1.4 No discriminación:

No se puede favorecer a ninguna implementación sobre

otras: la certificación ha de ser justa y sólo basarse en

motivos tecnológicos.

En la actualidad sólo se tienen en cuenta motivos

tecnológicos para pasar los TC. Esto no fue así hasta

hace unos meses, cuando entró en vigor JCP 2.6; hasta

entonces una implementación libre de un UJSR no podía

certificarse por el tipo de licencia de su código fuente.

5.1.5 Extensión o subconjunto:

Los estándares libres se pueden extender u ofrecer en

subconjunto, aunque en este caso puede negarse la

certificación.

Es posible implementar subconjuntos, superconjuntos, o

modificaciones de las especificaciones del JCP; por

ejemplo en [14] se recogen múltiples variaciones del

lenguaje Java, bytecode y/o JVM, normalmente

desarrolladas con fines científicos. En general no es

posible certificar subconjuntos ni modificaciones de las

especificaciones, aunque sí superconjuntos de ciertas

especificaciones. Así, por ejemplo, los distintos

vendedores de servidores de aplicaciones J2EE suelen

extender la especificación con características propias

para diferenciar sus productos de los de la competencia.

5.1.6 Defensa contra prácticas predatorias

Este punto es una concesión más que un requerimiento.

Los estándares libres pueden protegerse contra

modificaciones por parte de terceras partes para evitar

prácticas “embrace-and-extend”. Este tipo de prácticas

las suele llevar a cabo el vendedor predominante de un

estándar, el cual crea una extensión del estándar no

compatible con el original e impide mediante patentes y

copyright que los demás vendedores implementen estas

extensiones. Esto provoca que las implementaciones de

los demás vendedores no sean compatibles con las del

vendedor predominante y permiten a éste último crear

un monopolio sobre el estándar.

Dentro de los JSR, o del JCP, no se identifican defensas

contra ese tipo de prácticas. No obstante la certificación

de las implementaciones, así como la propiedad de Sun

de la marca “Java” y términos relacionados, que sólo se

pueden emplear tras certificarse, defienden a la

plataforma de estas prácticas. Esto es lo que sucedió en

1998 con la JVM de Microsoft [15], que no seguía la

Actas del II congreso javaHispano

93

Page 94: Actas del II congreso javaHispano

especificación de J2SE, por lo que Sun llevó a la

compañía de Redmon a los tribunales.

5.2 ¿Se cumplen los criterios de Perens?

El draft de Perens es el intento más serio y consensuado

que la comunidad del SL ha realizado para definir qué es

un estándar libre. Como se ha mostrado, las

especificaciones de la plataforma Java cumplen todos los

requerimientos de este borrador, todas sus buenas

prácticas y en varias ocasiones incluso van más allá, por

ejemplo, ofreciendo una certificación completa gratuita

a implementaciones sin ánimo de lucro.

En base a los criterios de Perens la plataforma Java, un

conjunto de especificaciones que definen una serie de

tecnologías, es libre. Esto no quiere decir que todas las

implementaciones de cada tecnología se distribuyan bajo

una licencia libre, pero la licencia de las

implementaciones nada tiene que ver con la libertad del

estándar; de hecho Perens nunca la menciona en sus

criterios.

Estos requerimientos no son suficientes, desde el punto

de vista del autor, para considerar un estándar libre.

Podrían definir un estándar “accesible”: puedo acceder a

él e implementarlo libremente, pero esto no es

suficiente: la única libertad que se garantiza es la de

seguir un camino (el marcado por el estándar) que

podría haber sido definido por una sola parte interesada

(empresa, organización o individuo), y no por todas las

partes interesadas. Por ello, para completar este estudio,

añadiremos dos criterios del documento de Krechmer a

los definidos por Perens.

5.3 Criterios de Krechmer

Krechmer, a diferencia de Perens, es un investigador del

laboratorio de Palo Alto, en California, USA. Su trabajo

ganó un premio en la competición “World Standards

Day” de 1998 y fue publicado en la revista Standards

Engineering. Este trabajo aborda la problemática de los

estándares en general, no sólo informáticos, y se escribió

pensando en organizaciones muy diferentes del JCP,

como ISO o ECMA, que también estandarizan objetos

materiales, y no sólo software. Por ello no todas las ideas

que hay tras los criterios académicos poseen sentido en

el mundo de lo intangible, y algunos requieren cierta

adaptación.

No obstante, en líneas generales, los criterios de

Krechemer incluyen a los de Perens y añaden más

requerimientos. Veamos cuales son los requerimientos

añadidos.

5.3.1 Apertura:

Todas las partes interesadas pueden participar en el

desarrollo del estándar.

Cualquier individuo puede formar parte del JCP, ya bien

sea a título personal o como representante de una

empresa u organización. En el caso de las organizaciones

sin ánimo de lucro e individuos esta participación es

completamente gratuita. Por otro lado, incluso sin

participar en el JCP se puede participar en la definición

de un único JSR, e incluso sin estar directamente

involucrado en el JCP, o en uno de sus JSR, cualquiera

puede acceder a la documentación de todos los JSR

mientras se están desarrollando, y enviar realimentación

al grupo de expertos.

5.1.6 Consenso y proceso de decisión justo:

En el proceso de definición del estándar todos los

intereses son discutidos y se llega a un acuerdo sin

dominación. Una votación puede ser empleada para

encontrar una solución.

Todos los intereses y contribuciones de las distintas

partes son considerados y discutidos en el JCP, y la

votación, de los CE, es la que finalmente decide qué se

incorpora y qué no se incorpora a las especificaciones

que forman la plataforma.

Sin embargo siempre hay un miembro de Sun

Microsystems en cada CE, que tiene derecho de veto

sobre todos los UJSR, y de los restantes 15 miembros 10

son propuestos por Sun, aunque deben de pasar una

ratificación pública. El PMO, aunque es un mero órgano

administrativo, está compuesto por asalariados de Sun, y

siempre hay un miembro de Sun en el comité de tres

personas que decide si una organización sin ánimo de

lucro puede o no pertenecer gratis al JCP o pasar el TC

sin pagar. Este criterio no se cumple por los privilegios

de uno de los participantes en el proceso de definición

de las especificaciones: Sun Microsystems

La solución a esta falla podría pasar por la gestión del

JPC por un organismo independiente, estilo Apache

Software Foundation. Esto evitaría que la plataforma se

mueva en una dirección que no es la más conveniente

para todas las partes interesadas, por causa de los

Actas del II congreso javaHispano

94

Page 95: Actas del II congreso javaHispano

intereses particulares de una empresa. Todos los

miembros de los CE deberían elegirse de un modo

democrático y debería desaparecer el derecho de veto.

6 Implementaciones de Referencia y Software Libre

Resulta evidente que la comunidad del SL se beneficiaría

de poseer un código libre en el que basar sus

implementaciones de las especificaciones, y es deseable

que este código fuese el de las propias IR. Por un lado

éstas son la primera implementación que se desarrolla, lo

que permitiría a la comunidad del SL disponer del código

base rápidamente. Por otro, si las todas las IR fuesen

libres serían testadas por multitud de desarrolladores, lo

que redundaría en una mejora de su portabilidad y su

calidad, y por consiguiente en la portabilidad y calidad

de las demás implementaciones: Jason Hunter afirma

que desde que Tomcat es la IR de los motores de Servlets

se han eliminado muchos bugs de portabilidad en los

motores comerciales.

La licencia de las IR desarrolladas por Sun son la principal

fuente de críticas a Java por parte del mundo del SL. Sin

embargo, como hemos mostrado, Java no es un

software, sino un conjunto de especificaciones. Alguna

de las implementaciones de estas especificaciones son

libres, otras no, pero esto no guarda relación con la

libertad de las especificaciones. Decir que Java no es libre

porque una de las implementaciones de una

especificación no licencia su código fuente mediante una

licencia libre es tan incoherente como decir que el

protocolo http no es libre porque Internet Explorer e

Internet Information Server no son libres.

La IR más polémica es sin duda la de J2SE. Efectivamente

la implementación de Sun no es libre, ni la de IBM,

BlackDown, Bea, etc. Sin embargo Kaffe [16], GCJ [17],

GNU Classpath [18], Japhar [19], Jikes [20], etc. sí son

libres, si bien es cierto que ninguna de ellas tiene en la

actualidad una funcionalidad suficiente para resultar

atractiva a los desarrolladores. En este sentido es la

propia comunidad del SL quien, por la causa que fuere,

está fallando a la hora de proveer una alternativa libre a

este estándar, del mismo modo que esta comunidad ha

creado alternativas libres para otros estándares (Mozilla

y Apache web server en el caso de http, por ejemplo).

En general el SL goza de un excelente estado de salud en

la plataforma Java: a pesar de ser un lenguaje de

programación relativamente reciente es el tercer

lenguaje de programación en Sourceforge, estando muy

cerca de de los primeros, C y C++; y existen una gran

cantidad de implementaciones libres de especificaciones

Java, suficientes para construir una compleja y completa

solución empresarial [21].

Cabe preguntarse porqué siendo la comunidad Java una

de las más prolíficas desarrollando SL las

implementaciones libres del entorno base van tan lentas.

La respuesta posiblemente sea que esta prolífera

comunidad, dado que dispone de varias

implementaciones gratuitas del entorno base que

poseen una calidad contrastada, prefiere centrarse en

desarrollar aplicaciones de más alto nivel, como librerías,

aplicaciones de escritorio, servidores de aplicaciones, etc.

que tienen un beneficio comparativo mucho mayor para

la sociedad. No obstante esta situación podría cambiar

en breve, debido a la intención del gobierno de Brasil de

desarrollar una implementación libre de J2SE [21], que

esperan tener lista para finales del 2005. De cumplirse

este objetivo el año 2005 podría ser el año en que la

comunidad del SL deje a un lado sus reparos y abrace

definitivamente a la plataforma Java.

La IR del J2SE, así como otras IR desarrolladas por Sun,

se distribuyen bajo licencia Sun Community Source

License (SCSL) [22]. Esta licencia permite ver el código

fuente del desarrollo, e incluso modificarlo, pero sólo

bajo ciertas condiciones, las cuales, en esencia, fuerzan a

que el producto modificado siga cumpliendo las

especificaciones de la máquina virtual, bytecode y

lenguaje Java. Su objetivo es evitar que la plataforma se

fragmente por causa de implementaciones del

compilador o máquina virtual no compatibles con las

especificaciones. Sun afirma que esta licencia “toma las

ventajas de los modelos de código abierto y propietarios,

y elimina sus inconvenientes” [22], ya que permite

acceder al código fuente libremente, con todos los

beneficios que para la comunidad y para la propia

plataforma conlleva, siempre que el acceso no atente

contra el principio básico de WORA.

Sin embargo, una vez que un individuo ha accedido al

código licenciado SCSL esta licencia le impide participar

en proyectos de código abierto, ya que el código que ha

visto es propiedad intelectual de Sun y no puede

emplear en proyectos libres lo que en él ha aprendido.

Además, si desea cobrar a sus usuarios por el trabajo que

ha realizado está obligado a pagar cuotas a Sun.

Evidentemente una licencia así dista mucho de poder

considerarse libre.

Actas del II congreso javaHispano

95

Page 96: Actas del II congreso javaHispano

¿Es necesaria una licencia de este tipo para algunas IR,

para proteger a la plataforma Java de la fragmentación?

Es una pregunta difícil de responder. Sun afirma que sí;

sin ella algunas empresas podrían aprovecharse de su

posición privilegiada en el mercado para imponer una

versión de la máquina virtual devaluada, o no

compatible con las demás. Este fue el caso de Microsoft,

quien en su día desarrolló una versión de la máquina

virtual y herramientas de desarrollo que permitían

acceder a ciertos servicios de Windows, lo que daba

lugar a crear aplicaciones que sólo funcionaban en este

sistema operativo [15]. Si la plataforma Java hubiese sido

completamente abierta nada hubiese podido detener a

Microsoft. Hoy en día la plataforma estaría fragmentada;

más de la mitad de los desarrolladores Java desarrollan

bajo Windows, y probablemente buena parte de ellos

emplearían las herramientas de Microsoft. Según Sun

SCSL vela para que esto no suceda.

Sin embargo Microsoft, u otra gran empresa, y la

comunidad de SL tienen recursos suficientes para

implementar la máquina virtual desde cero, sin

necesidad de basarse en ningún código. Es posible partir

de las especificaciones del lenguaje y máquina virtual

[24, 25] e implementar una variante de Java sin basarse

en ningún código, con lo que esta licencia pierde

bastante sentido.

Por otro lado no hay ningún indicio de fragmentación

dentro de la comunidad del SL: las implementaciones

libres de J2SE (y de cualquier otro JSR) siempre tratan de

adherirse a las especificaciones.

Sun a menudo alega que las múltiples distribuciones de

Linux prueban la comunidad del SL no es capaz de

reconocer que hay cosas que si se bifurcan pierden su

valor. Sin embargo parece que Sun se olvida del

tremendo esfuerzo que esta comunidad realiza a través

de Free Standards Group [12] para lograr que todas las

distribuciones de Linux, y otros sistema operativos *nix,

sigan una serie de estándares que garanticen la

compatibilidad entre distribuciones; y es que la

comunidad del SL sabe reconocer y respetar ciertas

cosas qué no se deben fragmentar.

En la práctica no hay indicios de que liberar el código

fuente de las IR suponga un riesgo de fragmentación

para la plataforma. Desde el punto de vista del autor lo

que realmente detiene a Sun es un problema de

naturaleza muy diferente: Sun, como empresa, necesita

Java, y necesita controlar Java a nivel empresarial. Las

plataformas Intel y compatibles, junto con Linux, están

comiendo el terreno de los servidores SPARC y Solaris.

Sun con Solaris10, un sistema operativo de código libre

que sale al mercado con una agresiva campaña de

precios que intenta competir con los servidores Linux de

RedHat, junto con la venta de hardware de bajo precio

basado en la arquitectura x86, va a tratar de cambiar

esta tendencia; pero el éxito de su nueva estrategia no

está garantizado.

En respuesta a esto Sun, una compañía que

tradicionalmente vivía del hardware, está apostando

fuertemente por los negocios basados en el software y

los servicios. El centro del negocio del software en Sun es

Java: recientemente hemos visto como Sun ha cambiado

el nombre de varios de sus productos para incluir el

nombre Java en ellos: Java Entreprise System, Java Studio

Creator, Sun Java System Application Server, Java

Desktop System. En el último la palabra Java se incluyó

en el nombre sólo como marketing, ya que Java Desktop

System es un S.O. de escritorio basado en Linux que

poco tiene que ver con Java. Menos aún tienen que ver

las Sun Java Workstation, unas estaciones de trabajo con

procesadores Opteron que no incluyen ningún tipo de

optimización para Java.

Por otro lado, Sun actualmente obtiene una cantidad de

ingresos considerable por las licencias de las tecnologías

Java; y su control sobre Java puede ayudarle a

posicionarse en un mercado emergente que a medio

plazo alcanzará un notable volumen: J2ME. Esto sin

olvidar el prestigio que le da a la compañía haber creado

y controlar la que actualmente es la principal tecnología

para crear aplicaciones de servidor y para dispositivos

móviles.

Siendo razonable, las empresas no son ONGs, no es

lógico que Sun desperdicie su posición ventajosa,

respecto a sus competidores y no explote una tecnología

en la que ha invertido tanto. A primera vista parece que

el mundo del SL busca un control sobre Java que

probablemente Sun no se pueda permitir ceder en este

momento sin dañar gravemente sus intereses.

Desde el punto de vista del autor existe un punto de

encuentro entre Sun y la comunidad del SL, que puede

permitir al primero seguir controlando Java a nivel

empresarial, y al segundo disponer del código fuente de

las IR. Este punto de encuentro es licenciar el código

SCSL mediante una doble licencia [26]. Un software que

se distribuye mediante una doble licencia se libera bajo

dos licencias, una libre con un “copyleft” [27] muy

fuerte (GPL o similar) y una propietaria. La libre satisfaría

Actas del II congreso javaHispano

96

Page 97: Actas del II congreso javaHispano

todas las demandas del mundo del SL, sin embargo no

sería aceptable, en general, para las empresas: éstas

verían su código infectado por el efecto “virus” de la

licencia con copyleft y tendrían que liberar su propio

desarrollo bajo una licencia libre. Dado que muy pocas

empresas estarán dispuestas a ello se verán obligadas a

optar por la licencia propietaria, y de este modo Sun

seguiría obteniendo beneficios y controlando Java a nivel

empresarial.

Al mismo tiempo Sun gana el apoyo de la comunidad del

SL y garantiza que toda distribución de Linux incluya

una JVM. A su vez la comunidad del SL obtiene un

valioso código en el cual basar sus desarrollos; dejaría de

tener reticencias sobre si algún día Sun empieza a cobrar

por Java o cambia sus condiciones de distribución; y

tendría garantías de que Java no se vería afectado por

una hipotética opa hostil, o cualquier otra adversidad,

que pueda padecer Sun y hacer que la propiedad

intelectual relacionada con la plataforma Java cambie de

dueño.

6.1 Unas palabras a favor de Sun

Sun a lo largo de los años ha mostrado, tanto

verbalmente como con sus acciones, que sus privilegios

sobre la plataforma Java son para hacer frente a ataques,

como sucedió en el caso de Microsoft, y no poner trabas

al desarrollo de SL en la plataforma Java. Durante mucho

tiempo Apache violó las normas del JCP, pudiendo haber

sido demandada por Sun. Lejos de ocurrir esto Apache

mantenía una excelente relación con Sun, quien le

apoyaba y financiaba sus desarrollos libres, y todos los

problemas se zanjaron modificando el JCP para legalizar

las actividades (desarrollo de una IR y TC bajo licencias

libres) que Apache llevaba tiempo realizando, pero que

de ningún modo suponían un riesgo para la

fragmentación de la plataforma.

Si bien Sun posee privilegios en el JCP al autor no le

consta ninguna evidencia de que los haya empleado con

otro fin que no fuese proteger la compatibilidad y

portabilidad de la plataforma.

También es evidente que Sun empuja cada vez más la

plataforma Java hacia la liberación: cada nueva versión

del JCP “libera” un poco más la plataforma. El JCP ha

ido evolucionando desde un estado en el que no era

posible realizar IR bajo licencias libres, los JSR podían

contener patentes y Sun poseía notables privilegios,

hasta una tolerancia total con el mundo del SL, al cual

incluso se incentiva dando opción a certificarse

gratuitamente, un rechazo frontal a cualquier patente no

licenciada Royalty Free en los JSR, y una auto-limitación

de los privilegios de Sun.

7 Conclusiones

La plataforma Java, un conjunto de especificaciones que

definen una serie de tecnologías, según los criterios

recogidos en el borrador de Perens, principal esfuerzo

del mundo del SL para definir qué es un estándar libre,

es libre. En este análisis las licencias de las IR, u otras

implementaciones, carecen de relevancia; de hecho

nunca se mencionan estas licencias en el documento de

Perens. Extendiendo estos criterios del modo que al

autor le ha parecido adecuado, se identifica un

problema: los privilegios que Sun posee sobre el JCP. A

pesar de ello no hay constancia de que Sun los haya

empleado con otro fin distinto de velar por la

plataforma.

Liberar el código SCSL bajo una doble licencia (SCSL y

GPL, por ejemplo) beneficiaría tanto al mundo del SL

como a Sun. Haría que Java fuese mejor acogido y

tuviese más apoyos dentro de la comunidad del SL, con

los consecuentes beneficios para la plataforma, y por

extensión para Sun; habría más desarrollos libres en y

para Java; y el código de las IR estaría más chequeado, lo

que incrementaría la portabilidad y fiabilidad de las IR y

de todas las implementaciones que se basan en ellas.

Por su parte Sun seguiría controlando y obteniendo

beneficios de Java a nivel empresarial, ya que la mayor

parte de las empresas no optarían por la licencia libre

por su efecto vírico. Sun podría ganar el apoyo del

mundo del SL sin perder su posición privilegiada en el

mercado Java.

Agradecimientos

Deseo expresar mi agradecimiento a Alvaro-Sánchez

Mariscal, Alberto Molperceres y Martín Pérez. Sin los

trabajos que vosotros realizasteis antes que el mío, sin

las discusiones que hemos mantenido y sin la

realimentación que he recibido de vosotros este trabajo

probablemente nunca habría visto la luz.

Actas del II congreso javaHispano

97

Page 98: Actas del II congreso javaHispano

Referencias

[1] Java Community Process, http://jcp.org.

[2] Bill Venners. Inside the Java Virtual Machine. McGraw-Hill Osborne Media, 2000.

[3] JCP 2.6, http://jcp.org/en/jsr/detail?id=215.

[4] Java Specification Request, http://jcp.org/en/jsr/overview.

[5] Robin Cover. Patents and Standars, http://xml.coverpages.org/patents.html.

[6] Free Software Foundation. http://www.fsf.org.

[7] Open Software Iniciative. http://www.opensource. org.

[8] Bruce Perens et al. Open Standards Principles and Practice. http://perens.com/OpenStandards/Definition.html.

[9] Ken Krechmer. The Principles of Open Standars, http://www.ses-standards.org/library/krechmer.pdf.

[10] OpenStandards.org. http://www.openstandards.org/.

[11] OpenStandards.net. http://www.openstandards.net/.

[12] Free Standards Group. http://freestandards.org/.

[13] Java Specification Participation Agreement, http://jcp.org/aboutJava/communityprocess/JSPA2.pdf.

[14] Múltiples variaciones del lenguaje Java, bytecode y JVM. http://www.robert-tolksdorf.de/vmlanguages.html.

[15] Declaración de James Gosling en el juicio contra Microsoft por su implementación fraudulenta de la JVM. http://java.sun.com/lawsuit/82198gosling.html.

[16] Kaffe, http://www.kaffe.org.

[17] GCJ, http://gcc.gnu.org/java/.

[18] Classpath, http://www.gnu.org/software/classpath/.

[19] Japhar, http://www.japhar.org.

[20] Jikes, http://www-124.ibm.com/developerworks/oss/jikesrvm/

[21] Alberto Molpeceres y Martín Pérez. Arquitectura empresarial y software libre, J2EE. http://www.javahispano.org/articles.article.action?id=70.

[22] Noticia de javaHispano. http://www.javahispano.org/news.item.action?id=673049882

[23] Sun Community Source License (SCSL), http://www.Sun.com/software/communitysource.

[24] Tim Lindholm y Frank Yellin. The JavaM Virtual Machine Specification. Addison Wesley. 1999.

[25] J. Gosling, B. Joy, G. Steele, G. Bracha. The Java Language Specification. Addison Wesley.

[26] Mikko Valimaki, Dual Licensing in Open Source Software Industry. http://www.soberit.hut.fi/~msvalima/dual_licensing.pdf.

[27] What is copyleft? http://www.gnu.org/copyleft/copyleft.html.

Actas del II congreso javaHispano

98

Page 99: Actas del II congreso javaHispano

Caso de uso: Empleo de tecnologías J2EE para el desarrollo de una plataforma

Rafael Pedraza Carmona

[email protected] Alberto Planas Domínguez

SEIRC/CESEAND [email protected]

Antonio Navarro González [email protected]

Benjamín de la Fuente Ranea

[email protected]

Jose David Fernández Rodríguez

[email protected]

Abstract

En esta presentación se pretende explicar la experiencia

que ha supuesto el desarrollo de una plataforma para la

gestión de ofertas y demandas tecnológicas, desarrollada

para dos organismos dependientes de la Consejería de

Innovación, Ciencia y Empresa de la Junta de Andalucía. El

objetivo principal de esta plataforma es servir de nexo de

unión entre aquellas empresas, grupos de investigación u

otros organismos que ofrecen algún producto con marcado

carácter innovador y aquellas otras que pueden ser

consumidores de estas tecnologías.

Las características más reseñables de este proyecto son el

uso en exclusiva de tecnologías de código abierto, el

empleo de las especificaciones J2EE para el módulo de

servidor (basado en JBoss, Tomcat, Axis, Lucene,...), el

innovador sistema de seguridad que facilita el acceso

segmentado a la información, un workflow para el control

de distintos grupos de trabajo y el desarrollo de una

interface de cliente Java basado en la plataforma Eclipse 3.

La conjunción de todas estas tecnologías, con el lenguaje

Java como hilo conductor, puede suponer un importante

punto de referencia para otros desarrolladores que

pretendan alcanzar un alto nivel tecnológico, basándose

para ello en la potencia y seguridad que aportan los

desarrollos de código abierto.

Keywords: J2EE, JBoss, JavaCC, Eclipse, Lucene, Hylafax, Software Libre, Seguridad.

1 Salto tecnológico con software libre

Properly Software cuenta en la actualidad cuenta con

una plantilla de diez personas, de las que la mitad

pertenecen al Departamento de Desarrollo. Los primeros

productos se realizaron exclusivamente con tecnología

de Microsoft (Visual Basic for Applications); si bien al

principio nos beneficiamos de la facilidad y simplicidad

de esta tecnología, pronto nos vimos en un callejón sin

salida: acorralados por unas necesidades y

especificaciones crecientes en complejidad y al mismo

tiempo limitados por unas herramientas que no nos

proporcionaban soluciones cuando pretendíamos

obtener algún resultado más allá de los casos de uso

más simples. Problemas de escalabilidad y la

obsolescencia de la tecnología empleada no nos deja

otra alternativa que pegar el salto tecnológico.

A la hora de tomar la decisión de hacia donde mover

nuestro marco de desarrollo los factores determinantes

para elegir J2EE y software libre, fueron razones

económicas (soluciones de Oracle, IBM y BEA son

excesivamente caras en un principio) y tecnológicas

(posibilidad de acceder al código y modificarlo, creciente

madurez de la tecnología, masa crítica de

desarrolladores, Java como lenguaje común para

aplicaciones de servidor y de cliente, presencia de J2EE

en la industria frente a otras soluciones).

Esta apuesta de futuro tenía que como consecuencia el

destinar recursos en tiempo y económicos a

investigación, partida para la que hasta ese momento no

había existido presupuesto.

2 Nuestro primer cliente: descripción del proyecto

Gracias a nuestro trabajo de investigación durante más

de un año, tenemos la opción de presentar una oferta al

Instituto de Fomento de Andalucía para el desarrollo de

una aplicación para la gestión de entidades y

transferencia de tecnología, así como herramientas que

Actas del II congreso javaHispano

99

Page 100: Actas del II congreso javaHispano

permitan obtener conclusiones estadísticas de los datos

cruzados.

Este proyecto consta de cuatro apartados principales:

• Gestión de entidades. Consideramos entidades las

empresas, los centros tecnológicos, grupos de

investigación y organismos. De cada entidad se

guarda información sobre su localización, una

descripción codificada de su actividad, personas de

contacto, proyectos en los que participan y derechos

de propiedad.

• Gestión de documentos de información

tecnológica. Aquí se almacenan y clasifican

documentos en formato XML validados por sus

respectivos esquemas XML y se transforman a HTML

mediante trasnformadores XLST.

• Herramienta de distribución de información. El

objetivo de ésta es la entrega selectiva de aquellos

documentos tecnológicos a aquellas entidades que lo

requieran o que puedan serles de interés. Los medios

de envío son el correo electrónico y el fax.

• Gestión de expedientes de patentes y marcas.

Este apartado está relacionado con las entidades y

almacena la información relativa a las diversas

actuaciones que se llevan a cabo con las mismas en

relación al patentado o registro de tecnologías.

Del análisis de requerimientos de la plataforma a

desarrollar determinamos las siguientes necesidades

principales:

• Seguridad: Además de los servicios de seguridad

proporcionados por el sistema operativo (firewall,

cifrado de comunicaciones por SSL) y de la base de

datos, nuestra plataforma aporta la posibilidad de

definir políticas de particionamiento basadas en los

datos (seguridad semántica).

• Variedad de clientes: Serán consumidores de los

servicios de la plataforma clientes web y clientes ricos

conectados por Internet con múltiples escenarios de

velocidad de conexión, proxies, firewalls y routers.

• Extensibilidad: Se prevé la incorporación de nueva

funcionalidad al sistema conforme se produzca la

implantación de los servicios existentes.

• Escalabilidad: Se plantea la necesidad de atender

solicitudes de clientes en un número creciente y al

mismo tiempo se espera un incremento considerable

de la información manejada.

3 Tecnologías de servidor

La tecnología J2EE abarca desde JDBC hasta JSP y los

EJBs. Toda esta cantidad de tecnologías está muy bien

documentada en la literatura técnica. Nosotros hemos

decidido usar EJBs, SOAP, JAAS, JNDI, JMX y Mbean.

Usamos el contenedor de aplicaciones libre JBoss 3.2.x.

Hemos tratado de seguir el estandar a traves de sus

BluePrints, pero en los escenarios donde JBoss o AXIS

nos proporcionaba una alternativa más limpia o

eficiente, no hemos dudado en hacer uso de ellas. Estos

casos pueden resumirse en:

• Consultas dinámicas. El cliente debe poder lanzar

consultas atendiendo a múltiples criterios de

búsqueda. Los mecanismos que proporciona J2EE

(findBy y select) no son lo suficientemente flexible.

JBoss propone una alernativa: DinamycQL. Podemos

construir la sentencia SQL que deseemos a partir de

los datos suministrados por el cliente.

• Modelo de Seguridad. El modelo basado en roles

no permite expresar restricciones basadas en datos.

Poder impedir el acceso de un usuario a las entidades

de una provincia determinada no es expresable con

una política de roles (ni declarativa ni programada).

Diseñamos un evaluador de expresiones (usando

gramáticas JJTree en JavaCC) que son invocados a

nivel de Beans por los SecurityProxy de JBoss. Estos

autorizan (o no) al usuario a retirar este dato.

• SOAP por HTTPS. Modificando WSDL4Java y

parametrizando los stubs generados por esta

herramienta de AXIS, logramos que el protocolo

XML-RCP SOAP viaje por un canal cifrado.

• Extensión del modelo de paso de parámetros de

configuración. La especificación EJB facilita un

medio de proporcionar valores de configuración

publicados en el directorio JNDI a las beans, sin

embargo este mecanismo requiere de un redeploy de

la aplicación ante un cambio de estos valores. Para

resolver esta problemática, además de otras

asociadas al tipo de datos que podemos gestionar,

hemos desarrollado un mecanismo mediante una

MBean que lee los valores de configuración desde un

fichero XML.

Actas del II congreso javaHispano

100

Page 101: Actas del II congreso javaHispano

3.1 Seguridad

3.1.1 Requerimientos

Un requisito de la aplicación que estamos desarrollando

es la de disponer de un mecanismo que permita

controlar las acciones que un usuario puede realizar

sobre los datos del sistema. Necesitamos restringir el

acceso de un usuario a un conjunto de campos de un

bean de entidad y necesitamos limitar el conjunto de

beans de entidad accesibles por ese usuario.

La primera restricción acotará las acciones que se pueden

realizar en un campo determinado p.ej: el usuario U

puede tener acceso de lectura a un campo pero no lo

puede modificar. Este tipo de limitaciones casan

perfectamente con el concepto de seguridad descrita en

la especificación J2EE [1]. En este modelo el usuario tiene

o no tiene derecho de llamada sobre un método de un

bean atendiendo a lo declarado en el fichero descriptor

del deploy.

Por contra, limitar el conjunto de beans de entidad sobre

los que un usuario debe tener conocimiento no puede

ser expresado por medio de la seguridad declarativa de

J2EE. El estándar no nos proporciona ninguna forma de

indicar que un usuario concreto, al solicitar la lista de

entidades de nuestro sistema mediante la llamada al

método getEntityList() localizado en un SLSB, esta nos

devuelva solo aquellas entidades que pertenezcan a una

provincia determinada. Es decir, no tenemos la

capacidad de expresar el dominio de datos de los

usuarios.

En la Tabla 1 podemos ver un resumen de las acciones

que debemos controlar y el receptor de dicha acción.

Tabla 1: Acciones básicas de un usuario

Acción Receptor

Acceso (S) Entidad

Lectura (R) Dato miembro

Escritura (W) Dato miembro

Consulta (X) Dato miembro

Las operaciones R,W y X se realizan sobre campos de una

entidad. Podemos leer el contenido de un campo,

modificarlo o lanzar una consulta con este campo como

criterio de búsqueda. La operación S determina qué

entidades pertenecen al dominio de datos de un usuario.

Podemos transformar estas acciones a predicados de la

forma expuesta en la Tabla 2. De esta manera un usuario

U puede leer el contenido de un campo F de una entidad

E si S(U,E) ^ R(U, F).

El predicado S, para poder ser evaluado sobre E necesita

de un conjunto de cláusulas o expresiones de restricción

de U sobre E. Es decir, tenemos que indicar el conjunto

de condiciones que una vez evaluadas nos digan si E

pertenece al dominio de este usuario.

Tabla 2: Predicados

Acción Descripción

S(U, E) Entidad E en dominio

R(U, F) Permiso de lectura de F

W(U, F) Permiso de modificación de F

X(U, F) Consultar por campo F

Repasados los requerimientos de nuestro sistema de

seguridad vemos que necesitamos de:

1. Una gramática para expresar restricciones de

dominio.

2. Un evaluador de restricciones.

3. Una descripción de los metadatos donde podemos

poner restricciones semánticas y permisos.

4. Un lugar estratégico en la arquitectura de nuestro

servidor donde determinar los permisos de usuario y

rechazar o aceptar la solicitudes del mismo.

5. Un modelo de datos donde alojar metadatos,

restricciones y usuarios.

Figura 1: Compilación de las restricciones.

Actas del II congreso javaHispano

101

Page 102: Actas del II congreso javaHispano

3.1.2 Restricciones y Gramáticas

Para poder expresar las restricciones de dominio de

manera adecuada hemos diseñado una gramática

sencilla que sea fácil de evaluar y de convertir a clausulas

WHERE en EJBQL por razones de optimización de las

consultas.

Hemos usado la herramienta JJTree de JavaCC [2] para

generar árboles AST evaluables mediante un recorrido en

postorden del mismo. Realmente el procedimiento de

evaluación se ha optimizado traduciendo el árbol AST a

una lista evaluable por medio de una pila (Fig. 1).

La gramática propuesta permite expresar restricciones

del tipo:

#contato.apellidos LIKE “Delgado%”

#facturacion > #empleados * 1000

Tenemos variables que vienen prefijadas por el símbolo

#, operadores, constantes, expresiones regulares, fechas,

booleanos, números y listas. Es decir, es lo

suficientemente completa para expresar un conjunto

importante de restricciones.

Para simplificar el uso por parte del administrador

encargado de definir estas restricciones de manera

dinámica, hemos incorporado la variable sin nombre (#)

para indicar 'el campo actual'. De esta manera la

expresión (# > 10) AND (# < 100) tiene un significado

diferente si se aplica al campo 'número de empleados' o

'edad'.

Con JJTree definimos los tokens que deberá encontrar el

analizador lexicográfico, la gramática que el parser

descendiente recursivo de JavaCC reconocerá, y las reglas

de creación del árbol AST. Especificar una gramática en

JavaCC es sencillo siempre que mantengamos en mente

algunas reglas sencillas como la de ir definiendo las

reglas de producción en orden inverso a la precedencia

de los operadores. Es decir, debemos indicar primero las

reglas de producción que tienen operadores de más baja

precedencia.

Recorrido el árbol en postorden (subárbol izquierdo -

subárbol derecho – raíz), y puesto los nodos del árbol de

manera lineal, la tarea del evaluador queda simplificada.

3.1.3 Modelo de datos

Disponemos ya de una herramienta para evaluar

restricciones. Para realizar su tarea el evaluador necesita

de los valores de las variables de su expresión. Estos

valores deben encontrarse en los beans de entidad sobre

los cuales estamos imponiendo restricciones. Estas a su

vez dependen del usuario que realiza la acción.

Vemos pues que necesitamos formalizar y almacenar las

relaciones y los datos (y metadatos) del modelo de

seguridad a través de un modelo de datos. Usaremos

diagrama Entidad Relación de la Figura 2 para guiarnos.

Figura 2: Diagrama ER de la seguridad.

Figura 3: Arquitectura general del sistema.

Hay restricciones sobre una entidad y sobre campos de la

entidad. Necesitamos recopilar en el sistema toda la

información que tengamos sobre los objetos susceptibles

de ser controlados. Hemos denominado a dichos objetos

del sistema, PDO (Persistent Data Object, Objetos de

Datos Persistentes). Cada PDO tiene un conjunto de

campos. Así por ejemplo, el PDO de un Contacto tiene

los campos Nombre, Dirección y Teléfono sobre los que

podremos poner restricciones y permisos.

Estos metadatos pueden generarse automáticamente

usando herramientas como XDoclet [3] o bien

introducidos en el sistema de manera manual. Por

desgracia generan una evidente redundancia, puesto

Actas del II congreso javaHispano

102

Page 103: Actas del II congreso javaHispano

que los datos securizables son los mismos que tenemos

en los Beans de Entidad (CMP y BMP), que a su vez

tienen una contrapartida en el modelo de datos global

de la aplicación.

Necesitamos almacenar los datos de los usuarios (login,

nombre, contraseña...) para poder activar el mecanismo

de autentificación y autorización de J2EE. Cada usuario

pertenece a un grupo de usuarios y este a su vez dispone

de varios roles dentro del sistema.

Almacenamos los datos correspondiente a los permisos

de lectura, escritura y consulta de los campos y las

restricciones que determinan el dominio de datos de un

usuario.

Los permisos se relacionan con un grupo de usuarios y

los campos de los PDOs. Por tanto para cada

grupo/campo indicamos los permisos R,W,X.

Las restricciones de dominio asocian el grupo de usuario

con el conjunto de restricciones sobre un PDO en

concreto. Ahora tenemos una estructura donde

recuperar la lista de restricciones que tenemos que

evaluar para saber si un usuario del sistema tiene o no

tiene permiso de acceder a un Bean de Entidad en

concreto.

3.1.4 JBoss y los SecurityProxy

Llegados a este punto disponemos de un evaluador de

restricciones y de un sistema que nos devuelve la lista de

restricciones a evaluar cuando un usuario quiere acceder

a una entidad. La cuestión ahora es en qué lugar de la

arquitectura de nuestro sistema sería más conveniente

realizar estas evaluaciones para aceptar o denegar la

acción.

La Figura 3 es una sobresimplificación de la arquitectura

del sistema. Vemos tres oportunidades donde colocar

nuestro mecanismo de seguridad.

Si lo colocamos en la capa más externa de todas, la capa

SOAP, por cada petición de un usuario, el sistema de

seguridad deberá atravesar toda la arquitectura para

recuperar los permisos, las restricciones y los datos

necesarios para evaluar dichas restricciones. Es evidente

que es poco óptimo y complejo. Además estamos

incorporando lógica en la capa de comunicaciones.

Incorporar la seguridad semántica dentro de la Session

Façade es factible. Estamos completamente dentro del

servidor, dentro del segmento de nuestra aplicación

donde recaen las decisiones de negocio. El problema

está en que la seguridad quedaría difuminada y

repartida en cada uno de los métodos de esta capa. La

dificultad en el mantenimiento e implementación sería

desaconsejable. Si bien tenemos a nuestra disposición

patrones de diseño como los Decorators y los Proxy que

pueden ayudarnos, quizás hay una alternativa mejor.

Si lográramos poner la seguridad en la capa de

persistencia, donde encontramos lo BMPs y CMPs de

nuestro sistema, la seguridad sería óptima. Ningún

acceso a los datos (excepto claro está, accediendo

directamente a la base de datos) podría saltarse las

comprobaciones de seguridad, y la situaríamos al mismo

nivel que la seguridad nativa de J2EE, mano a mano y

complementándose.

Para lograr este nivel de integración necesitaremos echar

mano de los interceptores. Aquí AOP nos puede ayudar,

pero decidimos, puesto que usamos JBoss 3.2.x, acceder

a las facilidades en la arquitectura de interceptores que

nos brinda este contenedor J2EE de código libre.

Los SecurityProxy [4] son unos interceptores a nivel de

beans que permiten separar la seguridad del resto de los

procedimientos. Este tipo de proxy es llamado antes de

cada invocación a los métodos del bean, es por tanto

una gran oportunidad para abortar esta llamada en caso

de que no se cumplan las restricciones de seguridad de

nuestro sistema. Hay dos tipos de SecurityProxy, uno que

tiene dos métodos (uno que se ejecuta para cada

llamada a los métodos Home (create, findBy y selects) y

otro para los métodos del objeto (postCreate, set, get y

remove)) y otro tiene el mismo interfaz que el CMP o

BMP que estamos interceptando.

Este modelo tiene la venta de poder navegar por las

relaciones de manera natural. Podemos establecer una

restricción sobre un elemento relacionado con el que

entramos tratando. Así puedo decir, por ejemplo, que un

usuario del sistema no puede acceder a las empresas que

tenga al menos un cliente de nombre Raul. Restricciones

así demuestran la potencia del planteamiento del

modelo, si bien presenta un problema: demasiadas

intercepciones pueden penalizar el rendimiento.

3.1.5 Optimizando el modelo

Si disponemos de un conjunto de restricciones

expresadas en un lenguaje similar al EJBQL, al menos en

lo que respecta a la cláusula WHERE ¿por qué no

construir una expresión que aplicada a cualquier

Actas del II congreso javaHispano

103

Page 104: Actas del II congreso javaHispano

consulta del sistema nos traiga el subconjunto de datos

accesibles por el usuario?

De esta manera limitamos el númer de excepciones

asegurando siempre la corrección del modelo. Aun sin

esta optimización el sistema impide desde su base el

acceso a los datos no autorizados.

Esta optimización hay que entenderla como tal: es la

única separación del modelo de seguridad, ya que hasta

ahora todo el asunto estaba localizado en los

interceptores.

4 Tecnologías auxiliares

Además de las tecnologías que nos proporciona J2EE,

hemos necesitado usar otras herramientas para cumplir

con las especificaciones de la plataforma desarrollada.

Esta tarea la hemos llevado a cabo mediante el

mecanismo de integración por Mbeans proporcionado

por JBoss. Los casos en los que ha sido necesaria esta

integración son:

4.1 Lucene

El modelo de datos de Lucene gira alrededor del

concepto de documento: un conjunto estático de

campos de texto (accesibles por nombre), que constituye

la unidad de indexación. En la compilación del índice se

le añaden documentos y en la búsqueda por palabras se

obtienen los documentos que satisfacen las condiciones

de las consultas.

Bajo esta funcionalidad de alto nivel hay un sofisticado

sistema cuyo conocimiento resulta fundamental cuando

se requiere (como en nuestro caso) modificar el sistema

en cierto grado para adaptarlo a nuestras necesidades.

En este sentido, ha resultado fundamental la posibilidad

de consultar el código fuente para poder comprender

Lucene de un modo más completo.

Para el sistema de notificación de modificaciones en los

documentos indexados se dispone de un acceso a la

capa de persistencia usando el patrón de diseño Session

façade. Aprovechamos la característica de proxys de

JBoss para interceptar las llamadas de actualización a los

beans. Este enfoque sugiere una aproximación a la

programación orientada a aspectos.

4.2 Hylafax

Hylafax es un servidor para el envío y recepción de faxes,

de código libre y amplio uso. Acepta peticiones de

transmisión vía sockets mediante un protocolo derivado

de FTP. Para facilitar la comunicación de nuestra

aplicación Java con Hylafax existen librerías también de

código libre. Nuestra interacción con el servidor Hylafax

se reduce a dos puntos muy concretos: el envío de faxes

y la determinación de si han sido enviados

correctamente.

Utilizamos HTML2PS para la transformación de nuestros

documentos HTML (generados a partir de los

documentos de información tecnológica mediante

transformadores XSLT) en documentos PostScript.

Para la comprobación del estado de los envíos usamos

una técnica de polling a intervalos regulares de tiempo.

5 Tecnologías de cliente

Inicialmente consideramos dos alternativas como

framework para la creación de nuestra aplicación de

escritorio. Una era NetBeans Platform, que permite la

construcción de aplicaciones Java con componentes

Swing. Descartamos esta solución debido a cuestiones

de rendimiento, consumo de memoria y aspecto general.

La otra alternativa, y la elegida, era Eclipse. Se basa en el

uso de componentes nativos del sistema operativo

cuando estos están disponibles (SWT) y un modelo muy

sencillo de datos para los componentes JFace.

5.1 Eclipse Rich Client Platform

Con RCP disponemos de todo un framework para la

escritura de aplicaciones de escritorio. Con el término

Rich Client Platform, la comunidad Eclipse se refiere al

mínimo conjunto de plugins que son necesarios para

construir una aplicación con un interfaz de usuario. Este

conjunto mínimo de plugins se reduce a tan solo dos:

org.eclipse.ui y org.eclipse.core runtime, sin embargo

podemos usar el resto del API ofrecida por Eclipse.

5.2 SWT (Standard Widget Toolkit)

SWT es una librería para crear interfaces de usuario en

Java. Se caracteriza por su integración con los

componentes gráficos del sistema operativo sobre el que

corre, lo que supone una apariencia unificada con el

resto de programas de esa plataforma y una velocidad

de ejecución nativa. Como contrapartida, se plantean

Actas del II congreso javaHispano

104

Page 105: Actas del II congreso javaHispano

problemas a la hora de hacer portable el código, aunque

ha sido solucionado bastante elegantemente. La manera

de acceder a los elementos gráficos del sistema

operativo se resuelve usando JNI (Java Native Interface),

accediendo a una serie de métodos escritos en C, que

son los que realmente acceden a los recursos del sistema

operativo. Por tanto, es necesario tener en cuenta dos

aspectos: la elección de las funciones que se proveerán

en la primera capa implementada en C, de manera que

hagan una abstracción genérica de las diferentes

plataformas (Windows, Motif, MacOs, etc…). Esta capa

debe ser tan delgada como sea posible para asegurar

eficiencia y que todo el código del manejo de widgets

esté implementado en Java. El segundo es aportar una

implementación diferente para cada plataforma,

generando una librería dinámica para cada una de ellas,

la cual será importada en tiempo de ejecución por la

librería de SWT mediante System.loadLibrary().

5.3 JFace

JFace es una librería para simplificar las tareas comunes

de la programación de interfaces de usuario. Está escrita

sobre SWT, pero no lo sustituye.

Las utilidades que suministra están clasificadas como

sigue:

• Viewers: manejan las pesadas tareas de rellenar,

ordenar, filtrar y actualizar los widgets.

• Acciones y Contribuciones: incorporan una

semántica para definir acciones de usuario.

• Imágenes y fuentes: patrones de manejo de

recursos de interfaces de usuario.

• Diálogos y wizards: estructuras para definir

interacciones complejas con el usuario.

6 Conclusiones

6.1 Consideraciones económicas

Debido al tamaño de nuestra empresa y a los limitados

recursos económicos disponibles para tareas de

investigación, el uso de software libre ha supuesto un

hito definitivo en nuestro salto tecnológico. Es de

resaltar que partíamos de una filosofía de programación

procedural, dependientes por completo de una solución

cerrada, sin posibilidades de crecimiento, desarrollada y

soportada por una única empresa. El software libre nos

ha permitido ser capaces de ofrecer un tipo de

soluciones al nivel de empresas de mucha más

embergadura y con un presupuesto muchísimo mayor.

Si hubiésemos pretendido implementar todo nuestro

desarrollo con software propietario, el coste hubiese

superado con creces nuestras posibilidades si sumamos

sistema operativo, gestor de bases de datos, servidor de

aplicaciones, servidor de fax, entorno de desarrollo, etc.

Por el contrario, siempre hemos encontrado una

alternativa libre con unas prestaciones en ocasiones

superiores a las ofrecidas por la alternativa propietaria.

6.2 Consideraciones técnicas

Disponer del código fuente de las herramientas usadas

ha sido, en determinados casos, decisivo para el éxito de

nuestro proyecto. En ocasiones en las que no

comprendíamos una determinada tecnología, la

inmersión en el código fuente nos ha facilitado la

información que no encontrábamos en la

documentación, además de corregir errores (tratamiento

de las conexiones HTTPS en Axis) y extender su

funcionalidad (modelo de documentos de Lucene, uso

de certificados digitales de la SDK de IBM en JBoss).

En nuestro desarrollo hemos empleado herramientas que

nos permiten asegurar características avanzadas en

rendimiento, seguridad, escalabilidad y fiabilidad.

Ejemplos son el SGBD PostgreSQL 7.4, el servidor de

aplicaciones J2EE certificado en su versión 4.0 JBoss, el

sistema operativo GNU/Linux o el contenedor de

aplicaciones web Tomcat 5.0.

6.3 Coste del aprendizaje

La desventaja del software libre radica en que,

generalmente, la documentación existente no suele ser

muy abundante o estar muy actualizada. Esto es debido

principalmente a que los esfuerzos de la comunidad de

desarrolladores se centran en la evolución del propio

código y no en facilitar la transmisión de esa

información. Como ejemplo de muy mala

documentación nombraremos el servidor Hylafax y el API

Java para su manejo, que prácticamente carecía de ella y

nos obligó a estudiar su código fuente para descubrir su

modo de funcionamiento. Por el contrario, el entorno de

desarrollo Eclipse tiene una muy buena y abundante

documentación.

El coste de aprendizaje, por tanto, es elevado pero se ve

compensado por el gran ahorro de costes en licencias.

Actas del II congreso javaHispano

105

Page 106: Actas del II congreso javaHispano

Referencias

[1] Sun Microsystems, Inc. J2EE Patfrom Specification. http://java.sun.com/j2ee/j2ee-1_4-fr-spec.pdf

[2] Java Compiler Compiler. https://javacc.dev.java.net/

[3] XDoclet. http://xdoclet.sourceforge.net

[4] Customized EJB security in JBoss. JavaWorld 15/02/2002 http://www.javaworld.com/javaworld/jw-02-2002/jw-0215-ejbsecurity.html

Actas del II congreso javaHispano

106

Page 107: Actas del II congreso javaHispano

Integración Continua utilizando herramientas Open Source

Jesús Pérez Sánchez www.agile-spain.com / Germinus

[email protected]

Abstract

En un entorno en el que el sector de servicios se ha vuelto

mucho más complejo, ser eficientes se convierte en una

exigencia para poder sobrevivir en este mercado. La

experiencia en el desarrollo de software a medida nos dice

que es habitual emplear mucho tiempo en integrar el

trabajo realizado por todo el equipo de desarrollo y, sobre

todo, en llevar este desarrollo del entorno de desarrollo a

producción.

La integración continua es un proceso que permite

comprobar continuamente que todos los cambios que lleva

cada uno de los desarrolladores no producen problemas de

integración con el código del resto del equipo. Los entornos

de integración continua construyen el software desde el

repositorio de fuentes y lo despliegan en un entorno de

integración sobre el que realizar pruebas unitarias o de

aceptación.

Implantar procesos de este tipo conlleva una inversión en

tiempo que será recuperada conforme avance el proyecto.

No obstante, esta inversión es cada vez más reducida

gracias a la disponibilidad de herramientas Open Source

que nos ofrecen soluciones de Integración Continua cada

vez más sencillas de implantar. Herramientas como

CruiseControl combinadas con Ant, Maven, Junit o DBUnit,

nos ofrecen la posibilidad de implantar un proceso de

Integración Continua pudiendo utilizar en este proceso

otras técnicas como la gestión de la configuración o

generación de informes de forma automática.

Palabras clave: Metodologías Ágiles, XP, Integración Continua, Herramientas Open Source, Agile-Spain,

1 Metodologías ágiles

Las metodologías ágiles han aparecido dentro del marco

de la Ingeniería del Software como una respuesta ante

los problemas de las metodologías tradicionales.

Problemas de adaptación a los entornos actuales de

proyectos, que se caracterizan por requisitos variables,

plazos breves así como presupuestos y recursos

ajustados. Las metodologías ágiles introducen cambios

importantes sobre los modelos existentes de ingeniería

del software, apoyándose en la experiencia de prácticas

aplicadas con éxito, que en muchos casos no resultan

novedosas.

La integración continua es una de las prácticas que

propone XP (eXtreme Programming []), una de las

metodologías ágiles más conocidas. Se trata de una

práctica que organiza el trabajo de integración a lo largo

de todo el proyecto. Implantar esta práctica supone un

cambio más dramático de lo que en principio parece,

dado que implica una nueva forma de entender el

desarrollo.

La integración continua es también un buen ejemplo de

una regla básica de un programador pragmático []:

“Intentar automatizar todo el trabajo repetitivo que

realiza”.

2 Integración Continua

¿Cuántas veces hemos oído a un desarrollador decir que

el código que ha desarrollado “funciona correctamente

en su máquina”? Ésta es la respuesta estándar cuando

un problema de integración ha sucedido.

Integración continua consiste en disponer de un proceso

automatizado que permita la construcción de nuestro

software desde las fuentes, que despliegue nuestro

software en un entorno similar al entorno final y que

lleve a cabo el conjunto de pruebas que validan su

correcto funcionamiento. Si nuestro sistema pasa

correctamente las pruebas podemos completar el

proceso desplegando nuestro software sobre un entorno

Actas del II congreso javaHispano

107

Page 108: Actas del II congreso javaHispano

donde pueda estar disponible. Este proceso debe poder

realizarse muchas veces al día.

El concepto que hay detrás de integración continua

(Continuous Integration o CI) es que se debe integrar el

desarrollo de una forma incremental y continua. Esto

permite encontrar problemas de integración y resolver

este tipo de problemas durante el desarrollo.

Integración continua es el término que se utiliza para dar

nombre a esta práctica dentro de la metodología de XP.

No obstante es una práctica que no es nueva y que es

aplicada en todo tipo de entornos de desarrollo de

software.

Para conseguir automatizar este proceso de

construcción, pruebas y despliegue de manera que se

realice diariamente muchas veces es necesario también:

• Almacenar las fuentes en un único lugar del que

pueda obtenerse la última versión del proyecto

(y versiones anteriores).

• Automatizar el proceso de construcción de

manera que se pueda, con un único comando,

construir todo el sistema a partir de las fuentes

• Automatizar las pruebas de forma que sea

posible y de forma automática, saber si todo

está bien o hay algún problema.

Introducir integración continua en un proyecto no suele

resultar sencillo. En muchos casos es realmente

complicado automatizar el conjunto de tareas repetitivas

que debemos realizar para conseguir una versión de

nuestro software. Es muy habitual que no existan

pruebas automatizadas asociadas al proyecto, lo que

implicará un esfuerzo considerable conseguir dotar a

nuestro software de este conjunto de pruebas. A pesar

de todo, el mayor esfuerzo que podíamos encontrar, el

desarrollo de la plataforma de integración, no es

necesario realizarlo en la actualidad gracias a la aparición

de plataformas abiertas de integración continua.

3 Beneficios de la Integración Continua

Introducir integración continua supone generalmente

para una organización, un cambio sustancial en su forma

de desarrollar software. Es una práctica que requiere

introducir cierta disciplina dentro del grupo de desarrollo

de software, que se verá compensada generalmente con

una mejora de la eficiencia. Probablemente sea una de

las prácticas más complicadas a nivel técnico de aplicar

de las que nos proponen XP.

Estos beneficios son los siguientes:

• Minimiza las sesiones de búsqueda de fallos a la

hora de integrar el código. Fallos realmente

complicados de encontrar dado que suelen ser

efectos colaterales de código que ha sido

desarrollado de manera independiente.

• Permite identificar fallos en el entorno de

producción en etapas tempranas. Esto permite

ser eficiente en los pasos a producción y evitar

los periodos de integración finales en los

entornos de producción.

• Minimización del tiempo de realimentación con

el cliente, al minimizar el paso de desarrollo a

un entorno de integración.

• Eficiencia del equipo de desarrollo: no es

necesario todo el conjunto de pruebas en el

entorno local, minimiza el tiempo de paso a

producción.

• Aumenta la confianza en el cdigo subido al

control de versiones.

4 Plataforma Open-Source

Implantar Integración Continua es una tarea de una

cierta complejidad técnica. Automatizar todo el proceso

que hemos descrito anteriormente sin apoyarnos en

ninguna herramienta resultaría bastante costoso.

En la actualidad no es necesario desarrollar

herramientas propias que permitan esta automatización

desde cero, dado que existen ya una serie de frameworks

que ofrecen soporte para esta práctica. Podemos

encontrar herramientas comerciales y herramientas

Open-Source.

El movimiento de Open-Source se ha consolidado en la

actualidad como un punto de referencia para cualquier

desarrollo. El extenso conjunto de herramientas, la

calidad y el espectacular avance que se puede observar

en muchos de los proyectos ha hecho que, hoy en día,

muchos de estos desarrollos se hayan convertido en

estándares (Struts, Ant, etc..). Resulta una ventaja

competitiva la utilización de estas soluciones en lugar de

tratar de desarrollar soluciones similares pero

propietarias. Es complicado que soluciones propietarias

puedan competir en funcionalidad con las soluciones

Actas del II congreso javaHispano

108

Page 109: Actas del II congreso javaHispano

libres cuyo coste de desarrollo es cero. Unas soluciones

cuya funcionalidad esta en continua evolución y que nos

permitirán evolucionar tecnológicamente con ellas.

Para Integración continua podemos encontrar diferentes

soluciones tanto Comerciales como Open-Source:

• CruiseControl (Open-Source)

• AntHill(Comercial/Open-Source)

• DamageControl

El más extendido de estos frameworks de integración es

Cruise-Control que ha sido desarrollado por una de las

empresas más importantes dentro del movimiento ágil,

ThoughtWorks, por lo que supone probablemente la

mejor forma de introducirse en esta práctica.

4.1 CruiseControl

Cruisecontrol es un framework que nos va a permitir

implementar dentro de nuestro proyecto un proceso de

integración continua. Este framework se apoya en otras

herramientas que se describen a continuación

4.1.1 Control de Versiones

Para poder implantar una herramienta de integración

continua la primera condición es tener un repositorio

con todas las fuentes del proyecto. Existen diferentes

repositorios de control de versiones como CVS,

Subversión, ClearCase, VisualSourceSafe, etc. Cada uno

de estos repositorios tiene características diferentes que

tendremos que evaluar cuando decidamos implantarlo

en nuestro proyecto. Uno de los mas implantados y que

es utilizado en la mayoría de los proyecto de Open

Source es CVS. No obstante y en los últimos tiempos,

parece que está siendo desplazada por Subversión que

ofrece unas funcionalidades para trabajar con diferentes

ramas de trabajo mucho mas potentes.

Utilizar Control de Versiones es una práctica se hace

especialmente imprescindible cuando se trabaja en

entornos colaborativos y en los que se desarrolla de una

forma evolutiva para que el software pueda estar

disponible desde las primeras versiones. Estas dos

razones han hecho de estos sistemas el corazón de los

proyecto de Software Libre.

El control de versiones contiene toda la historia de los

cambios que se han ido produciendo en nuestro código.

Éste nos permitirá replicar cualquier momento de

nuestro desarrollo y por tanto generar cualquier de

nuestro software que hayamos generado hace tiempo

siempre para construir el software únicamente nos

hayamos apoyado en las fuentes que existían el control

de versiones.

Introducir el control de versiones en un equipo es una

práctica que supone un cambio sustancial en la forma de

trabajar de un equipo. A partir de ahora nuestro trabajo

se compartirá con nuestros compañeros diariamente, lo

que nos impondrá ciertas buenas practicas que

permitirán que todos podamos trabajar eficientemente.

Será importante ser cuidadoso con el código que

introducimos en el control de versiones para evitar que

nuestros compañeros al actualizarse tengan problemas

para seguir desarrollando.

La experiencia al final nos hace ver que lo necesitaremos

incluso cuando realicemos desarrollos individuales y en

los que tengamos una única entrega, dado que es fácil

descubrir que es una herramienta muy potente para

desarrollar (permite poder identificar los cambios que se

hicieron en las fuentes desde una fecha determinada,

evita la proliferación de copias de seguridad de nuestro

código, identifica claramente cuál es la ultima versión,

etc…).

4.1.2 Pruebas Automatizadas

El siguiente paso para poder llegar a implantar

Integración Continua es el desarrollo de pruebas

automatizadas.

Implantar esta práctica es uno de los retos más difíciles

que nos encontraremos en la implantación de la

integración continua.

Desarrollar un conjunto de pruebas completas de

nuestro sistema es una tarea cuya complejidad

dependerá del entorno de ejecución de nuestra

aplicación y de las interacciones con sistemas externos.

Un conjunto de pruebas completas de nuestro sistema

implicaría tener diferentes conjuntos de pruebas:

• Pruebas Unitarias

• Pruebas de Rendimiento

• Pruebas de Integración con sistemas externos

• Pruebas de Diseño (Accesibilidad)

• Pruebas Funcionales

En el modelo tradicional de desarrollo este tipo de

pruebas se realizaban una vez finalizado el desarrollo. No

Actas del II congreso javaHispano

109

Page 110: Actas del II congreso javaHispano

obstante este enfoque no suele funcionar en la mayoría

de los proyectos de desarrollo y es realmente poco

efectivo.

Desarrollar pruebas automáticas nos permite comprobar

en cualquier momento y ejecutando la ‘suite’ de pruebas

si nuestro sistema cumple con la funcionalidad

implementada hasta el momento. Esta facilidad es

tremendamente útil durante el desarrollo, puesto que

nos permitirá desarrollar cambios con seguridad, sin

tener que pagar el esfuerzo de volver a probar todo.

Dejar las pruebas para el final del desarrollo nos privará

de esta ventaja.

La herramienta más extendida y la que cuenta con una

comunidad más activa para el desarrollo de pruebas es

JUnit. JUnit nos ofrece un framework sobre el que

desarrollar las pruebas de nuestro sistema de una forma

homogénea, que nos permitirá que nuestro conjunto de

pruebas crezca de una forma ordenada. Este framework

se acompaña de un conjunto de utilidades que permitirá

presentar los resultados en diferentes formatos (XML,

HTML). Una de las características más importantes de

esta plataforma es que nos ofrece la posibilidad de

ejecutar todo el conjunto de pruebas ejecutando un

único comando y que se integra perfectamente con

lenguajes de scripting como es Ant.

Esta combinación es muy potente dado que podremos

incorporar de manera automática las pruebas de nuestro

software al proceso en el que se construye una nueva

versión. De esta manera podremos asegurar, cuando

creemos una nueva versión de nuestro software o

cuando lo despleguemos sobre un entorno, que el

código pasó previamente las pruebas que certifican el

funcionamiento correcto de todas las funcionalidades.

Sobre JUnit se han desarrollado muchas extensiones

realmente útiles que ofrecen librerías para facilitar cierto

tipo de pruebas. Especialmente interesante son las

librerias de:

• JUnitPerf: Introducir pruebas de rendimiento

durante el desarrollo es muy sencillo y muy

valioso, especialmente en aquellas clases criticas

como las de acceso a Basede Datos, las que

realicen operaciones pesadas (algoritmos,

parseo de XML, integración con otros sistemas

externos, etc..)

• Cactus: Para permitir pruebas realizadas

directamente sobre el contenedor. Pruebas

unitarias sobre el entorno final

• StrutsTestCase: Extensión para hacer pruebas

unitarias sobre actions de struts

• DBUnit: Suite para pruebas muy dependientes

de los datos almacenados en Bases de Datos

• HttpUnit, JUnit, CanooWebTest: Pruebas

directamente contra la aplicación web

Realizar pruebas puede ser complicado pero siempre es

posible. Incluso en entornos muy específicos en los que

no encontremos suites que simulen el comportamiento

de los elementos externos, es posible desarrollarnos

mediante Mock-Objects clase que simulen estos

comportamientos. En muchos casos este tipo de pruebas

nos servirán no solamente para comprobar que nuestras

clases funcionan correctamente, si no para acelerar

nuestro desarrollo, al no tener la necesidad de realizar

las pruebas sobre esos entornos.

4.1.3 Automatización (Scripting)

Una vez llegados a este punto nos encontramos en

situación de poder comenzar a pensar en automatizar

todas las tareas que realizamos, para conseguir construir

nuestro sistema a partir del código que hemos

desarrollado y lograr que sea desplegado y este

disponible para poder ser utilizado.

Una de las claves de la eficiencia en el desarrollo es el

nivel de automatización que hemos conseguido

implantar en todas las tareas relacionadas con el

desarrollo.

Pero aún siendo la mejora de la eficiencia una excelente

razón para decidir comenzar a automatizar los procesos

de nuestro desarrollo hay otra razón que muchas veces

queda oculta y que es en mi opinión mucho más

importante: la capacidad de poder repetir los procesos

de una manera exacta. El desarrollo de software es una

disciplina con un alto grado de incertidumbre. Al gran

número de variables que afectan a un desarrollo

(Sistemas Operativos, Base de Datos, Integración con

sistemas externos, Servidores de aplicaciones) en muchas

ocasiones añadimos nosotros todavía más incertidumbre

al introducir procesos manuales al proceso de

construcción del software.

Conseguir que nuestro proceso de despliegue sea

idéntico en todas las ocasiones nos asegurará poder

replicar o repetir cualquier proceso previo que hubiera

sido exitoso.

Actas del II congreso javaHispano

110

Page 111: Actas del II congreso javaHispano

Pero automatizar un proceso puede ser una tarea que

conlleve mucho esfuerzo. Entonces la pregunta es ¿Qué

debemos automatizar?. En nuestra opinión cualquier

proceso manual que vayamos a realizar en más de una

ocasión.

Para automatizar todos estos procesos Java cuenta con

una herramienta ANT que nos permite llevar a cabo la

mayoría de las tareas que realizamos de forma manual

con una consola. Tareas como copiar ficheros, compilar

nuestras clases, hacer FTP a otras máquinas con

versiones de nuestro software, ejecutar nuestras

pruebas, pueden ser automatizadas con ANT.

ANT es un framework para realizar scripts a partir de una

serie de tareas predefinidas. Este framework es muy

extensible y permite introducir nuevas tareas si fueran

necesario. Aunque la extensa contribución de la

comunidad de ANT hace que sea complicado encontrar

tareas que no estén implementadas dentro de ANT.

El problema con Ant reside en que las tareas que ofrece

son de muy bajo nivel y deberemos invertir en tiempo en

automatizar nuestras tareas mas comunes de desarrollo

Para resolver este problema ha surgido Maven que nos

ofrece una posible implementación de todas estas tareas

de alto nivel. (preguntar a Dani)

4.1.3 Configuración de CruiseControl

Hay diferentes formas de abordar un proyecto de

desarrollo. Nos encontramos desde proyectos en los que

todo el equipo desarrolla en misma máquina, hasta

proyectos en los que cada desarrollador tiene asignado

su ordenador personal y una máquina adicional similar al

entorno de desarrollo. También nos encontramos

empresas que tiene un servicio de control de versiones

general para todos los proyectos y otras en las que cada

proyecto es responsable de su repositorio de control de

versiones.

Para detallar el proceso de integración continua y la

configuración de CruiseControl supondremos un entorno

en el que cada usuario desarrollar en su entorno local,

que existe una maquina dedicada al control de versiones

y que existen dos entornos comunes integración y

producción.

Cada desarrollador dispondrá de un entorno local en el

cual realizará la mayor parte del trabajo de desarrollo. En

este entorno dispondrá de un entorno simulado del

entorno real a escala reducida. Dependiendo de los

sistemas involucrados con el software que se desarrolla

en algunos casos se compartirá alguno de estos sistemas

en lugar de instalarlos en el entorno local. También es

posible solucionar este problema utilizando clases que

en lugar de utilizar los servicios remotos, simulen este

comportamiento.

Cada desarrollador subirá periódicamente sus nuevos

desarrollos al entorno de control de versiones e irá

actualizándose con las modificaciones que vayan

realizando otros miembros del equipo.

El entorno de integración continua (en nuestro caso

CruiseControl) suele estar instalado en el entorno de

integración. Esto permite que podamos desplegar de

una manera sencilla el software sobre el entorno de

integración una vez que ha pasado las pruebas.

Para instalar CruiseControl es necesario tener en cuenta

los siguientes directorios

En estos directorios se instalar

• CruiseControl: En este directorio instalaremos la

herramienta de integración continua.

• Tomcat: Tenemos la opción de publicar los

resultados mediante una aplicación web. Esto

Actas del II congreso javaHispano

111

Page 112: Actas del II congreso javaHispano

nos obligará a instalar un contenedor de

servlets como Tomcat

• Fuentes del Proyecto: Este directorio lo

utilizaremos para que CruiseControl tenga su

copia del código del control de versiones.

CruiseControl no tiene una arquitectura muy sofisticada,

consta de un proceso que cada cierto tiempo

comprobará una serie de condiciones para lanzar una

serie de acciones.

La otra parte de la arquitectura es la herramienta de

publicación de la actividad de este proceso. Esta

herramienta esta desarrollada en Java y esta

empaquetada en un war. Instalando un Tomcat y

desplegando esta aplicación configurada correctamente

tendremos disponibles via web la información de la

actividad del proceso principal de CruiseControl

Toda la configuración de CruiseControl esta centralizada

en un único fichero. En este fichero podremos configurar

todas las propiedades del proceso de integración

continua. Las más importantes son:

• ModificationSet: En este propiedad se especifica

a CruiseControl cuales son las condiciones que

se tiene que producir para lanzar un proceso de

construcción, despliegue y pruebas del

Software. Generalmente lo asociaremos a

cambios en nuestro control de Versiones

• Schedule: En esta propiedad especificaremos

cada cuanto tiempo el control de versiones

deberá realizar un build como máximo si no se

produce alguna condición que lo lance. En esta

propiedad se detalla exactamente el script de

Ant y el objetivo que deberá lanzar

CruiseControl que es el que automatiza todo el

proceso de construcción, despliegue y pruebas.

• Publisher: En esta propiedad especificamos

como notificaremos de los resultados de prueba

al equipo de desarrollo.

5 Experiencia Real

La experiencia real aplicando integración continua

demuestra que aplicar esta práctica supone una pequeña

revolución en la forma de desarrollar. Implica un cambio

de filosofía para el que es necesario un periodo de

adaptación.

La Integración continua es una práctica de la que todo el

mundo ha oído hablar pero que muy pocos equipos de

desarrollo aplican (incluyendo aquellos que utilizan

metodologías ágiles como XP)

¿A que se debe que no este nada extendida?.

5.1 Problemas implantando Integración Continua

El principal problema que nos hemos encontrado al

aplicarla es que en la mayoría de los casos supone la

introducción de otras prácticas en las que se apoya.

• Control de Versiones: Necesitamos tener control

de versiones de nuestro código, de manera que

podamos recuperar cualquier versión del

proyecto. Esta es una practica muy extendida y

no suele suponer un problema.

• Pruebas Automáticas: La integración continua

pierde gran parte de su valor si no existen.

Implantar esta práctica una vez comenzado el

proyecto es muy costoso y supone una parada

del desarrollo. Incluir pruebas automatizadas al

proyecto y programar desarrollando pruebas es

uno de los cambios de filosofía necesario si

queremos implantar Integración Continua

• Construcción y despliegue automatizados: Esta

es una de las tareas que tendremos que realizar

si no existen los scripts que permitan llevar a

cabo este proceso sin intervención manual.

5.2 Buenas Prácticas

La integración continua impone un desarrollo en equipo

más disciplinado. En muchos proyectos no se es

consciente de que se trabaja en equipo hasta que llega el

momento de la integración final.

La integración continua hace que nuestro desarrollo sea

incremental. En cada momento nuestro sistema ofrecerá

una serie de funcionalidades que serán las que prueben

nuestro conjunto de pruebas automáticas. Los nuevos

desarrollos añadirán nuevas funcionalidades evitando

que las anteriores dejen de funcionar. Cuando el

conjunto de funcionalidades de nuestro sistema ofrezca

la posibilidad de tener un software coherente con nuevas

posibilidades, entonces en ese caso deberemos crear una

nueva versión.

Actas del II congreso javaHispano

112

Page 113: Actas del II congreso javaHispano

Para que este desarrollo incremental funcione

correctamente la experiencia nos dice que es necesario

seguir las siguientes prácticas:

• Desarrollar pruebas a medida que se desarrollan

funcionalidades: Cada nueva funcionalidad que

se integre en el control de Versiones deberá

tener su conjunto de pruebas. Cuando se

modifique alguna funcionalidad también será

necesario modificar su conjunto de pruebas.

Utilizar desarrollo dirigido por pruebas TDD

facilita esta tarea.

• Política de Semáforos: Una vez que utilicemos

integración continua el sistema nos informara

del estado del software De esta manera

recibiremos continuamente notificaciones

cuando el código que tengamos en nuestro

repositorio de versiones no pase las pruebas. En

ese caso tendremos el semáforo en rojo para

subir nuevo código al CVS. Esto nos permitirá

no introducir nuevas clases antes de identificar

cuales han sido las clases responsables de este

problema. Si el control de versiones nos ha

enviado un mail avisándonos del éxito de

nuestras pruebas, entonces en ese momento el

semáforo estar verde para subir nuevo código

estará en Verde.

• Tiempo máximo de solución de errores en el

control de Versiones: En la medida de lo posible

tenemos que minimizar el tiempo en que el

desarrollo que hay en el control de versiones no

pasa las pruebas. En aquellos casos en los que

sea difícil arreglar un problema que hemos

detectado una vez subido el código al control

de versiones la mejor opción es volver al código

de la versión anterior.

• Minimizar el tiempo entre integraciones: Uno

de los objetivos principales de la integración

continua es realizar continuamente

integraciones, cuanto mas a menudo se realicen

mejor funcionara el proceso. Por este motivo

hay que intentar que este tiempo sea el mínimo

posible. Por este motivo tenemos que conseguir

mantener nuestro proceso automático lo mas

rápido posible, tratando de reducir el tiempo

que consumen las pruebas y el tiempo que

consume el despliegue.

• Coordinar aquellos cambios o

reestructuraciones que influyan en gran parte

del código: La integración continua implica un

elevado grado de coordinación. Estas

coordinaciones son especialmente importantes

en aquellas modificaciones que vayan a afectar

a muchos módulos. En estos casos muchas

veces es más eficiente hacer este tipo de

cambios desde situaciones estables, para

intentar evitar efectos colaterales. Es posible

que estos cambios sean realizados por cada

programador en los módulos en los que esta

trabajando.

• Responsable del entorno de integración

continua: Nuestra experiencia aplicando

Integración Continua es que es muy

conveniente tener un responsable encargado de

que este entorno funcione correctamente y de

que el equipo esta siguiendo las reglas

anteriores. Esta persona será la responsable de

arreglar aquellos errores que surgen sin que se

haya realizado ningún cambio por el entorno en

el que se ejecutan los test.

• Los mails que genera el Control de Versiones no

son Spam: Nuestra experiencia nos dice que hay

ciertos periodos en los que se produce cierta

inestabilidad en el entorno de control de

versiones. En esos momentos es cuando al

recibir muchos emails de sistema de integración

continua nos sentimos tentado de tratar este

como Spam (redirigiendolo a la carpeta de

borrar o a otra carpeta que no consultaremos).

Estas situaciones tenemos que tratar de

evitarlas tratando de solucionar el problema de

la inestabilidad lo antes posible e

interrumpiendo temporalmente el envió de

correos. Los correos nuestro sistema de

integración continua debemos tratar de

atenderlo lo antes posible para conseguir todos

lo beneficios de implantar esta práctica.

• Conseguir que nuestras pruebas, prueben el

sistema y sean fáciles de mantener Es

importante que nuestras pruebas nos ayuden a

conocer que nuestro sistema funciona. En

muchos casos desarrollamos conjuntos de

pruebas que nos dan muy poca información

sobre las funcionalidades de nuestro sistema y

con un gran coste de mantenimiento. No

Actas del II congreso javaHispano

113

Page 114: Actas del II congreso javaHispano

conseguir este propósito nos hará plantearnos

en ocasiones si merece la pena en esta situación

seguir manteniendo nuestro entorno de

integración continua.

7 Conclusiones: El poder de la Automatización.

Es realmente sorprendente que equipos que

desarrollan programas para automatizar el trabajo

en otros ámbitos, en muchas ocasiones no utilicen

esta capacidad para automatizar su propio trabajo

en lo posible. Detrás de los equipos más eficientes

de desarrollo encontraremos generalmente un alto

grado de automatización de su trabajo.

La integración continua es una práctica cuya

implementación implica automatizar una de las

tareas más pesadas y complejas de predecir: el

proceso de integración del desarrollo en un entorno

similar al final. Para implantar esta práctica el

movimiento de Software libre nos proporciona

herramientas muy potentes (CruiseControl, Ant,

CVS, Junit, etc) que facilitarán este camino.

La Integración continua nos permitirá detectar de

manera temprana posibles problemas de integración

que puede tener soluciones muy complejas a

posteriori. Alcanzaremos un grado de confianza alto

sobre nuestro desarrollo al validarlo continuamente,

con el conjunto de pruebas, en un entorno similar al

final.

La integración continua minimizará el tiempo de

puesta en producción acortando el ciclo desde que

nuestro cliente nos pide un desarrollo nuevo o un

cambio hasta que puede tenerlo en producción. Esto

nos hará ser mucho mas ágiles con nuestro cliente,

mostrándole en cada momento como evoluciona el

desarrollo para que, junto con él, podamos llegar a

la solución que mas valor le aporte.

Referencias

[1] Kent Beck, Extreme Programming Explained: Embrace Change, Addison-Wesley, 1999.

[2] Martin Fowler y Matthew Foemmel. Título del Articulo: Continuous integration, ThoughtWorkshttp://www.martinfowler.com/articles/continuous Integration.html

[3] Lasse Koskela. . Driving on CruiseControl., JavaRach Journal, September

2004http://www.javaranch.com/journal/200409/DrivingOnCruiseControl_Part1.htm

[4] CVS. https://www.cvshome.org/

[5] Subversion. http://subversion.tigris.org/

[6] Ant. http://ant.apache.org/

[7] Maven http://maven.apache.org/

[8] DBUnit . http://dbunit.sourceforge.net/

[9] Easy Mock Objects http://www.easymock.org/ l

Actas del II congreso javaHispano

114

Page 115: Actas del II congreso javaHispano
Page 116: Actas del II congreso javaHispano