Actas del II congreso javaHispano

Anuncio
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
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
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
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
5
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
6
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.
7
Actas del II congreso javaHispano
8
Actas del II congreso javaHispano
__________________________________________________________________________________
__________________________________________________________________________________
9
Actas del II congreso javaHispano
10
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.
11
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.
12
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.
13
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.
14
Actas del II congreso javaHispano
¿Has dicho Middleware?
Miguel Valdes-Faura
Abstract
15
Actas del II congreso javaHispano
16
Actas del II congreso javaHispano
__________________________________________________________________________________
__________________________________________________________________________________
17
Actas del II congreso javaHispano
18
Actas del II congreso javaHispano
SIMToolkit: la última frontera para la integración total, en la palma
de tu mano.
Alejandro Seco Calero
David Fraga Aydillo
aseco@die.upm.es
dfraga@die.upm.es
nuestro móvil de bolsillo podemos, a día de hoy,
Abstract
desde mandar un mensaje de texto, navegar por un
buscador
El avance de la tecnología móvil parece no tener freno a día
de
Internet
o
establecer
una
videoconferencia con nuestro colega americano,
terminales
de hoy. Los termina
les móviles se renuevan cada menos
hasta descargarnos nuestra melodía favorita y todo
tiempo y las posibilidades que ofrecen se multiplican de
ello lo asumiremos como servicios en su mayor
igual manera. En este documento realizaremos un análisis
parte
tecnologías
de las posibilidades ofrecidas por tecnolog
ías incluídas en
habituales.
Así
pues
el
término
comunicaciones junto a movilidad van unidos de
nuestro móvil como son Java Card (SIMToolkit) y J2ME. La
forma irrevocable.
tecnología
tecnologí
a SIMToolkit nos ofrece la posibilidad de crear en
El planteamiento desde el punto de vista de usuario
la tarjeta
tarjeta SIM una aplicación diseñada por nosotros,
nosotros, y
menú.. P
Por
realizar desde ella operaciones desde nuestro menú
or
de cara a su terminal parece sencillo. Los requisitos
otro lado el desarrollo de aplicaciones para J2ME (midlets)
fundamentales son interfaces gráficas vistosas, y
todo
nos presenta to
do el potencial del API de MIDP tanto a
funcionalidades cada vez más avanzadas, pero la
nivel gráfico como de comunicaciones. Estudiaremos
base de todos estos elementos se desarrolla en un
oportunidades que nos ofrecen ambas plataformas de cara
motor de procesado cada vez más potente. Cada vez
comunicación
exterior,, y de igual forma
a la comunicaci
ón con el exterior
más, el terminal móvil adquiere funcionalidades
analizaremos la viabilidad de unir ambos mundos. Las
similares a un ordenador convencional, y entre ellas
posibilidades
pos
ibilidades que se nos ofrecen son muy amplias, y en
hay que destacar las librerías de comunicaciones.
base a ellas propondremos líneas futuras y de aplicación.
Nuestro sistema va a estar dotado de un amplio
abanico de posibilidades a la hora de conectarse al
Keywords: J2ME, Midlet, MIDP, GPRS, CSD, JavaCard,
exterior.
Smart Card, SMS, evento, proactivo, SIMToolkit(STK).
posibles redes de comunicaciones que nos vamos a
Deberemos tener siempre presente las
encontrar: red GSM, red GPRS (sobre GSM), red
UMTS, Internet, redes privadas y redes de área
1
Introducción al entorno de aplicación
aplicación
personal (IrDa, Bluetooth, … ). Hoy en día una de las
redes de mayor uso es la red GPRS dimensionada
Hoy en día nos movemos cada vez más en un
sobre su predecesora GSM.
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
Figura 1: Estructura de red GPRS
19
Actas del II congreso javaHispano
Otro factor clave en el mundo de las tecnologías
La tarjeta SIM va a ser considerada como un
móviles es la tendencia hacia la universalización y
periférico adicional dentro de los elementos que
estandarización de dispositivos. Los terminales van
componen un terminal móvil. La tarjeta adquirirá un
a ser desarrollados bajo plataformas muy similares,
carácter pasivo. Este rol pasivo se define así ya que
de forma que el desarrollo de aplicaciones para cada
para que la tarjeta pueda enviar información hacia el
uno de ellos sea idéntico y no sea necesario
exterior (terminal) recurrimos a un petición de
realizarlo y adaptarlo para cada uno.
estado continua desde el terminal y en nuestra
respuesta desde la tarjeta le indicaremos nuestro
Entre las tecnologías que mejor resumen todos los
estado junto con la invocación de alguna función a
aspectos que se han reseñado encontramos aquellas
realizar (comandos proactivos).
que se sitúan tanto a nivel de terminal: Java2 ME
(plataforma miembro de la familia de productos Java
Entenderemos nuestro terminal móvil como un
adaptado a terminales o dispositivos de reducido
microprocesador
tamaño) y Symbian (sistema operativo desarrollado
actualmente cada vez son más potentes) con el cual
por un consorcio de compañías del sector, el cual
interactuamos mediante distintos periféricos, tales
permite la programación de aplicaciones por parte
como
del usuario), como tecnologías en el ámbito de
concretamente, nuestra tarjeta SIM.
nuestra tarjeta SIM: Java Card [2] (plataforma de Java
uno de estos elementos adquiere gran importancia
adaptada para tarjetas inteligentes o smart cards,
para la composición final del dispositivo, pero
que cuenta con su propia maquina virtual) y, a un
especialmente la tarjeta SIM será la que nos permita
nivel superior a Java Card, encontramos la interfaz
comunicarnos hacia el exterior. Desde la tarjeta
SIMToolkit [1], que adapta las posibilidades de una
vamos a poder controlar el acceso a la red. La
tarjeta SIM al mundo Java. Adentrándonos en el
operadora nos va a permitir acceder a sus servicios a
mundo de la tarjeta SIM lo que nos ofrece el entorno
través de la clave encriptada que reside en nuestra
de desarrollo SIMToolkit [1] es la unión de los
tarjeta.
mundos de tarjetas inteligentes y nuestro terminal.
mecanismos de comunicaciones de nuestra red:
Mediante una API propia vamos a ser capaces de
SMS,
desarrollar
señalizaciones, etc. No solo se va a poder acceder a
aplicaciones
que
puedan
correr
en
el
(como
teclado,
Así
el
pues
llamadas
hemos
display,
tendremos
de
comentado,
voz,
audífono
o,
Por ello cada
acceso
llamadas
de
a
los
datos,
nuestra tarjeta, y que posean una interfaz de cara al
estos servicios si no además la tarjeta va a disponer
usuario en el display del móvil, siendo los aspectos
de acceso a información sensible como agenda o
visuales opcionales.
mensajes, almacenados en la propia SIM
Veamos a continuación la estructura de la familia de
Desde el punto de vista del terminal vamos a
productos Java 2 , donde aparecen desmarcados en
concebir el dispositivo como un pequeño ordenador
la
desde
parte
derecha
los
productos
destinados
a
dispositivos móviles y smart cards.
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
Figura 2 : Plataforma Java 2
manteniendo el núcleo del API de J2ME siempre que
20
Actas del II congreso javaHispano
este estuviera soportado (con su correspondiente
cuestión.
Tras el envío de un APDU se esperan
perfil MIDP)
respuestas con un formato concreto y sencillo (Ej,
0x9000 Ok). Será sobre este perfil dónde interactúe
Así pues, con todo lo aquí planteado, parece verse
STK definiendo un protocolo entre ambos lados. En
que delante de nosotros tenemos dos mundos a
el cuerpo de los datos enviados en el APDU
simple vista diferentes, en primer lugar el lado
mandaremos información con cabeceras definidas
terminal, y por otro el lado tarjeta SIM. Los dos nos
por STK, y de la misma forma en los códigos de
ofrecen numerosas posibilidades, y por ello, nuestro
respuesta podrá venir información adicional con
primer objetivo será el control de ambos campos,
formato STK. La comunicación en éste ámbito se va
desde la programación básica general hasta el
a ver diferenciada por el origen y destino que tenga,
control de librería de comunicaciones. Una vez
así, diferenciaremos entre mensajes de SIM a
alcanzado este objetivo nuestra línea de desarrollo
terminal y vicerversa, dando lugar respectivamente,
tenderá hacia la unión de ambos entornos, con el fin
a los que llamaremos comandos proactivos y
de poder procesar información desde un lado y
eventos.
recibirla en el otro, obtener conectividad desde la
Comandos Proactivos
tarjeta SIM hacia nuestro terminal móvil y viceversa.
Un comando proactivo es aquel lanzado por la
2
SIMToolkit (STK)
tarjeta SIM y cuyo destino es el propio terminal,
pidiéndole a éste que realice alguna operación
La comunicación entre nuestra tarjeta y el terminal
concreta. Existen 31 comandos proactivos posibles
móvil se lleva acabo gracias a una API concreta, STK.
para
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.
•
aplicación para Smart Cards deberemos implementar
una serie de funciones guión pues el entorno de
estos
métodos
a
nuestro
Smart-card
commands,
destinado
interoperar
con
tarjetas
otras
•
encontramos:
General
communications
interfaz
vamos a entrar a desarrollar por entender que
portadoras soportadas.
forman parte del entorno de tarjetas inteligentes y
•
salen del contexto de nuestro artículo. Destacar que
primera
implementa
la
a
SIM
System
para
los
distintos
Commands,
commands,
tipos
orientados
de
a
la
sincronización con el terminal y la red.
una diferencia de STK respecto a Java Card simple es
la
Los
Applications commands, para desarrollar
install(), destroy(), o process(). Métodos que no
que
terminal.
introducidas en nuestro terminal.
ejecución estará predeterminado para buscar estas
Entre
enviar
aplicaciones típicas de STK.
Puntualizaremos que para el desarrollo de una
funciones.
poder
dividiremos en 4 categorias:
función
Una vez nos adentramos dentro del bloque de datos
processToolkit() , similar a process() en Java Card y
del APDU, observamos que los comandos proactivos
será ésta la que se ejecute en el momento de
están
activación de nuestra aplicación.
bloques que vamos a encontrar dentro del Data load
divididos
en
una
nueva
estructura.
Los
del APDU son denominados TLV (Tag-Length-
El formato de transferencia de información desde
Values). Cada TLV va a venir definido por un campo
una Smart Card (SIM en nuestro caso) recibe el
Tag, a modo de identificador, un campo de bytes
nombre de APDU. Por consiguiente el terminal móvil
indicando el tamaño del siguiente campo, y el
también va a esperar recibir este tipo de paquetes
campo value, donde encontraremos el verdadero
desde nuestra tarjeta. La estructura de un ADPU es
valor a nivel de datos.
muy sencilla. Poseen dos campos iniciales, uno de
Podremos encontrar varios
TLV’s concatenados. A modo de ejemplo: podemos
clase de instrucción (CLA) y otro de de operación a
encontrarnos un Data load en un APDU(SIM->MOVIL)
ejecutar (INS), seguidos de dos campos P1 y P2 que
donde un primer TLV nos indique el tipo de
serán parámetros opcionales, Le (tamaño en bytes
proactivo que se envía (Tag = comando proactivo,
de la respuesta esperada, Lc (tamaño en bytes del
length = 1, value = Display text), un segundo TLV
campo de datos) adjunto y el campo de datos en
21
Actas del II congreso javaHispano
indicaría una seria de comandos que no entramos a
-La tarjeta como elemento de almacenaje que es,
valorar y un tercer TLV nos indicaría qué texto
estará compuesta por un sistema de ficheros con
queremos sacar por el display.
unas características especiales, debido a su limitada
capacidad, pudiendo acceder a este sistema de
ficheros desde el API de STK (apertura, lectura,
SIM
Móvil
escritura)
TLV
–Seremos capaces de poder acceder a los mensajes
TLV
STK
cortos almacenados en nuestra tarjeta y de igual
Tag Length Value
Tag Length Value
manera a almacenamientos de mensajes entrantes
CLA INS P1 P2
Lc
CLA INS P1 P2
Data
APDU
Lc
en la misma. (recordamos que tendremos manejo
Data
total sobre mensajes entrantes, evento SMS-PP)
APDU
Smart Card
-Podremos editar y obtener información de las
entradas en nuestra agenda personal SIM.
Figura 3 : Estructura del APDU
-La
Eventos
tarjeta
telefónica
convencional
guarda
en
memoria las últimas llamadas de voz realizadas, y
Mas allá de poder dar la tarjeta SIM órdenes a
de la misma forma podremos acceder a ellas para
nuestro terminal a través de comandos proactivos, la
comprobar sus destinatarios y duraciones.
propia tarjeta podrá registrar una serie de eventos
GESTIÓN DE LOS PROCESOS DE COMUNICACIÓN CON
EL TERMINAL
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
El planteamiento que acabamos de realizar para el
lógico
para
desarrollo de aplicaciones desde STK (información
implementar. Recordamos que la tarjeta adquiere un
de la tarjeta) no lleva acabo transferencia de
modo pasivo a la hora de poder enviar proactivos
información a través de eventos y proactivos. Todo
hacia el terminal. Realizando una caracterización de
se realiza desde la misma tarjeta la cual obtiene
los
información propia,
y
por
eventos
ello
su
disponibles
mayor
facilidad
según
su
categoría,
aunque si necesitamos de
proactivos para el envío de esta información hasta el
encontramos los siguientes grupos principales:
display (proactivo DISPLAY TEXT).
-
Notificaciones de mensajes.
-
Notificaciones de llamadas, y datos.
-
Notificaciones de actividad o selecciones de
con las funciones de comunicación de nuestro móvil.
menú por parte del usuario.
Los
-
Las posibilidades que nos ofrece STK son mucho
más amplias, y gran parte de ellas tienen que ver
a
desarrollos
continuación
y
a
valorar
funcionalidades
canales
fundamentales
de
flujo
de
información (llamadas de voz, SMS y conexiones de
Cambios de estado a nivel de celda
Entraremos
tres
datos)
podrán
ser
controlados
desde
nuestra
aplicación STK.
posibles
aplicando
EL API STK nos ofrece la posibilidad de controlar
directamente los conceptos aquí descritos.
tanto los mensajes cortos salientes como los
entrantes, pudiendo actuar dependiendo de su
naturaleza de forma distinta. Existirán dos eventos
GESTIÓN DE LA INFORMACIÓN DE LA TARJETA
distintos para cada una de las direcciones de envío
Como hemos mencionado anteriormente contamos
del mensaje (saliente-entrante). Puntualizaremos,
en nuestro desarrollo con el API ofrecido por STK.
que al igual que todos los procesos anteriormente
Este API nos ofrecerá el entorno necesario para
descritos, estas funcionalidades quedan fuera de la
manejar comandos proactivos y eventos. De la
vista del usuario, al cual podremos informarle de las
misma
funciones llevadas acabo a
forma
nos
ampliará
posibilidades
al
través del display
únicamente (proactivo que deberemos ejecutar).
ofrecernos una interfaz Java que nos permitirá
acceder a la información contenido en la tarjeta SIM:
22
Actas del II congreso javaHispano
DESARROLLOS/APLICACIONES
Si nuestros mensajes pueden estar bajo control, no
iban a ser menos las llamadas. Tendremos la
Veremos
posibilidad de realizar llamadas a un número
permite
de datos desde nuestro terminal. Los canales
aplicaciones
obtener
una
visión
completa
de
las
funcionalidades implementadas en nuestro terminal,
permitidos serán bien CSD o GPRS, determinando en
tanto a nivel de proactivos como de eventos. Nos
una configuración de parámetros sus respectivas
muestra
calidades de servicios. Seremos capaces por tanto de
por
personalizado
abrir el canal de datos, obtener información y
cerrar
las
MECapabilities:
MECapabilities El desarrollo de esta aplicación nos
Por último destacar la posibilidad de controlar flujos
posteriormente
de
resumida:
una determinada llamada llega a nuestro móvil.
para
algunas
realizadas basándonos en toda la estructura aquí
concreto, y de tomar acciones a nuestra elección si
enviarla
ahora
pantalla
de
el
los
listado
completo
proactivos/eventos
o
que
deseemos consultar y en base a una consulta en el
nosotros
propio móvil nos confirma si está soportado.
mismos el propio canal. Reseñamos numerosas
dificultades que hemos encontrado en este aspecto
Los mecanismos para el desarrollo de esta pequeña
en los desarrollos realizamos en el laboratorio por
aplicación son muy simples. Basándonos en el
motivos de configuración de operador, soporte de
evento de acción por parte del usuario (cuando entra
transmisión
y
en nuestro menú de aplicación) interactuamos con él
configuración adecuada de las calidades de servicio
de
datos
por
parte
del
móvil,
presentándole gráficamente el menú selección desde
en el propio canal.
el que puede chequear cualquier opción. Desde el
API de STK accedemos a la clase ME Profile y desde
OTRAS FUNCIONALIDADES
Que
nuestra
tarjeta
SIM
allí
soporte
JavaCard
SIMToolkit no implica que el terminal móvil en el que
esté
insertada
soporte
todos
los
GestSIM:
GestSIM
comandos
queremos
indicar
que,
cada
chequear
Completa
administración,
proactivos y eventos que están contemplados. Con
ello
podremos
cualquier
tipo
de
evento/proactivo que deseemos.
y
aplicación
almacenaje
y
basada
en
la
transferencia
de
mensajes y en el control de entradas en la agenda de
terminal,
la propia tarjeta. Funcionalidades que podemos
dependiendo de sus prestaciones nos va a ofrecer la
aportar con esta aplicación son, por ejemplo, la
posibilidad de interactuar con la tarjeta hasta cierto
actualización de contactos de nuestra agenda al
punto. Se implementarán por parte de fabricante un
llegar a una región distinta donde nuestra empresa
cierto grupo de proactivos y eventos a los que
posee un grupo de comerciales distintos a la zona
responder. Se ha realizado una pequeña aplicación
de donde provenimos. Se accede también al control
capaz de mostrarnos por pantalla aquellos servicios
de llamadas realizadas y salientes, siendo accesibles
que el móvil es capaz de procesar.
para estas los contactos almacenados en nuestra
Una vez planteado que nuestro móvil no tiene
tarjeta. A través del manejo de información de
porqué implementar todas las funciones, veremos
mensajes
algunas
localización derivadas de nuestra posición en el
de
las
más
interesantes
de
cara
al
se
pueden
obtener
funciones
de
programador STK, aparte de las ya vistas:
momento de envío.
-Presentación en pantalla de texto, menús, listas y
Toda la aplicación se basa en la gestión de los
formularios.
procesos
de
comunicación
anteriormente explicados,
-Respuestas a eventos del usuario: acción sobre
del
terminal
junto con la interfaz
gráfico común a todas las aplicaciones de cara al
teclas.
usuario.
-Obtención de parámetro de localización (a nivel de
ConGPRS:
ConGPRS Aplicación aún en proceso de depuración,
celdas).
que nos permite establecer una conexión de datos a
-Obtención de nivel de potencia de las bases más
un servidor remoto, enviando información contenida
cercanas.
en nuestro móvil y cerrando posteriormente todas
las comunicaciones.
23
Actas del II congreso javaHispano
proactivos
tarjetas inteligentes, y entendemos, desde nuestro
destinados a canales de datos (clase ‘e’) , y de igual
punto de vista, que queda mucho camino por
forma presentamos los datos por nuestro display.
recorrer para STK, teniendo ya una buena base para
Para
este
desarrollo
utilizamos
los
empezar a andar.
3
Integración
Integración
Por último hacer mención al entorno de desarrollo
de todo nuestro sistema aquí descrito, y es que por
J2ME bajo sus perfiles y configuraciones nos permite
muy bien que diseñemos una applet para nuestra
el desarrollo de aplicaciones dentro del propio
tarjeta SIM, deberemos transferirla e instalarla en la
terminal. Estas aplicaciones pueden barajar desde
tarjeta. SIMAlliance es la organización que ha
interfaces gráficos hasta soporte de comunicaciones
estandarizado sus herramientas, de uso público y
vía sockets TCP, es por ello que hemos trabajado en
con las que recientemente estamos trabajando. Son
este sentido para poder explotar especialmente los
recursos de
de fácil acceso, pero al estar poco extendida entre
comunicaciones del móvil. Hemos
desarrolladores esta tecnología, las dificultades que
realizado implementaciones de aplicaciones cliente-
aún se encuentran para el desarrollo no son pocas.
servidor vía sockets TCP, vía protocolo http y envíorecepción de datagramas. Hasta la versión MIDP2.0
5
estas son, junto con https, las implementaciones
posibles de elementos de comunicaciones.
Líneas futuras
No cabe duda que hoy en día la telefonía móvil ha
Las plataformas desarrolladas en este artículo (J2ME
adquirido un ritmo de crecimiento tecnológico muy
y STK) nos ofrecen altas posibilidades de desarrollo
alto. Es por ello por lo que movernos de un concepto
respectivamente, estando cada una de ellas en
tecnológico a otro nos lleva muy poco tiempo y, a
mundos distintos a pesar de convivir dentro del
día de hoy, la telefonía de tercera generación (3G)
propio terminal (móvil y tarjeta). Nos planteamos la
está demasiado cerca nuestra como para obviarla.
unión de ambos mundos con las ventajas que ello
La adaptación de STK a este nuevo entorno es
conllevaría. Realizaríamos la ampliación de cada una
necesaria pues todas nuestras tarjetas en breve
de las API’s por separado, pudiendo interactuar
estarán
desde nuestro móvil con la tarjeta SIM y viceversa.
conectarse a la red UMTS.
Entre los mecanismos para realizar esta integración
Orientándonos hacia la integración de STK junto a
podemos encontrar por ejemplo la implementación
J2ME, dos plataformas que ya empiezan a convivir
de protocolos propios que utilizando eventos de
en
captura de llamadas o de mensajes, y de esta forma
estudio muy interesantes como el JSR de J2ME,
insertadas
nuestro
en
teléfonos
dispositivos,
capaces
encontramos
vías
de
de
interactuar con nuestra tarjeta. Este planteamiento
SATSA. Security and Trust Services API for J2ME es la
sería sólo en una dirección de comunicación.
especifiación de un paquete de java que puede tener
Dejamos al lector discernir sobre posibles formas de
mucho que decir en el futuro de estas tecnologías.
comunicación desde nuestra tarjeta al terminal.
Con un final Release por parte del JCP de Sun, y a
tan sólo la espera de su implementación por parte
4
de un fabricante en algún dispositivo, SATSA ofrece
Conclusiones
vías de comunicación a nivel APDU desde nuestro
Dos mundos tan aparentemente separados, pero tan
terminal hasta nuestra tarjeta SIM. Seremos capaces
cerca el uno del otro. Siguiendo la línea de la
de, realizando la programación de nuestro módulo
integración total o parcial de ambas tecnologías
Java, realizar ediciones en los mensajes o agenda de
observamos las posibilidades que ofrecerían ambas
la tarjeta, enviar eventos determinados o realizar un
juntas. La implementación, especialmente en STK, a
propio protocolo de comunicaciones entre ambos
priori puede parecer algo mas difusa que el
dispositivos con el fin de acceder a información en
desarrollo en J2ME pues en esta última la aportación
un momento determinado. Dejaremos en manos del
por la comunidad Java en esta es mucho mayor, pero
lector analizar y evaluar otras posibles aplicaciones
gracias a las normas GSM [5][6], y a la transparencia
bajo esta línea de desarrollo.
y practicidad de lo que se pretende hacer, resulta
muy agradecido el desarrollo de aplicaciones para
24
Actas del II congreso javaHispano
Agradecimientos
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
Especialmente
día
a
sonriendo
David,
la
del
figura
laboratorio.
que
mejor
representa a un tutor cercano, y siempre dispuesto a
ayudar, gracias. Va por vosotros.
Referencias
[1] Scott B. Guthery, Mary J. Cronin. Mobile Application
Development with SMS and the SIM Toolkit. McGrawHill.
[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”
25
Actas del II congreso javaHispano
26
Actas del II congreso javaHispano
Aplicaciones de tratamiento de imagen en terminales
J2ME con cámara
Jonatan Tierno Alvite
Celeste Campo Vázquez
jonatan@it.uc3m.es
celeste@it.uc3m.es
En este trabajo hemos utilizado terminales de la Serie 60
Abstract
de Nokia, principalmente el Nokia 6600, y también el
Nokia 3650. Como lenguaje de programación, hemos
En este documento vamos a estudiar la posibilidad de
realizar aplicaciones de tratamiento de imagen sobre
utilizado Java 2 Micro Edition (J2ME).
teléfonos móviles con cámara incorporada en J2ME. Esto
Uno de los posibles usos de estas aplicaciones es la
implica implementar algoritmos que típicamente tienen alta
ayuda
carga
en
manipular información visual sobre un dispositivo que la
memoria y capacidad de proceso, y además sobre J2ME,
gente usa en su vida cotidiana. Por ello, hemos
que suele ser considerado un lenguaje de programación
implementado dos aplicaciones dirigidas a este fin: La
poco eficiente, y de posibilidades limitadas dada su
primera es un Lector de Colores, que permitirá conocer a
reducida API. Hemos realizado dos aplicaciones de ejemplo:
un usuario ciego los colores de un objeto al que dirija la
Un Lector de Colores y un Detector de Movimiento. Después
cámara, por ejemplo, una prenda de ropa. La segunda es
hemos realizado un estudio sobre las capacidades de un
un Detector de Movimiento, con el que podrá saber
terminal concreto, tanto en capacidad de proceso como en
cuando alguien entra en una habitación, cuando se
la calidad de imagen que podemos obtener. Con estos
apaga o enciende la luz, etcétera.
computacional
sobre
dispositivos
limitados
datos sacamos conclusiones sobre qué tipo de aplicaciones
a
invidentes,
pues
estamos
hablando
de
El resto del documento se organiza de la siguiente
es posible realizar en estas condiciones y para qué otras es
forma: En la sección
necesario buscar una plataforma más potente.
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
Keywords: Tratamiento de imagen, teléfonos móviles
con cámara, MMAPI, ayuda a invidentes.
información de las imágenes de la cámara. Tras esto, se
describe la implementación de dos aplicaciones de
1
ejemplo: el Lector de Colores, al que dedicaremos la
Introducción
sección 3 y el Detector de Movimiento, que se tratará en
Hoy en día muchos teléfonos móviles (y algunas PDAs)
la sección 4. En una segunda parte del proyecto,
pueden obtener información no sólo de las redes de
realizamos un estudio de un terminal concreto (el Nokia
comunicaciones a las que están conectados, si no
6600), para determinar su capacidad de ejecutar
también del entorno físico, mediante grabación de audio
aplicaciones de tratamiento de imagen. En la sección 5
y video.
hablaremos sobre el acceso a la calidad de las imágenes
disponibles, y en la sección 6, sobre la capacidad de
Hasta ahora, y centrándonos en la cámara de fotos y
proceso y la memoria del terminal. Por último, en la
vídeo, esta nueva capacidad se ha utilizado de la misma
sección 7 usaremos todos los datos obtenidos para
forma que en una cámara convencional: se guarda la
discutir sobre qué aplicaciones pueden implementarse
fotografía o el archivo de vídeo en el terminal para
sobre estos terminales y cuáles no.
recuperarla más tarde o para enviarla a otro dispositivo.
En este documento vamos a discutir la posibilidad de
2
Mobile Media API (MMAPI) y el
acceso a la cámara
realizar un cierto procesado sobre esa información antes
de pasar los resultados al usuario.
La Mobile Media API (MMAPI) es una librería opcional de
J2ME que permite acceder a cualquier tipo de contenido
27
Actas del II congreso javaHispano
multimedia (imágenes, audio, video), tanto local como
complicada o incluso inabordable por razones de
remotamente. También es el interfaz J2ME hacia
eficiencia.
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
3
Lector de Colores
tipo de acceso Java hacia la cámara.
El lector de colores permite a un usuario conocer los
La MMAPI consigue tratar diversos tipos de contenidos
colores del objeto que esté enfocando con la cámara del
móvil. De esta forma un invidente puede separar la ropa
de la misma manera mediante un alto nivel de
blanca de la de color para hacer la colada, por ejemplo.
abstracción que esconde las operaciones a bajo nivel que
La aplicación está dividida en los siguientes bloques:
realiza el sistema operativo. La MMAPI ofrece un interfaz
captura y muestreo de los pixels, clustering, decisión y
común a la lectura de datos desde cualquier fuente y en
cualquier formato mediante un Identificador Uniforme
por último, comunicación de resultados.
de recursos (URI), que definirá el dispositivo y los
Al inicializar la aplicación, la cámara se pone en
parámetros de reproducción. El acceso a la cámara se
funcionamiento, y cuando el usuario apunta a un objeto
realiza con el URI especial de captura “capture://video”.
Con
la
llamada
y pulsa el botón de acción,
key);”
“System.getProperty(String
realizamos la captura y
muestreo de la imagen. En este bloque tomamos una
podemos saber si nuestro dispositivo permite captura de
fotografía
mediante
el
getSnapshot,
método
y
video o no, y en qué formatos.
accedemos a los pixels según hemos descrito más arriba.
El programador manejará una realización del interfaz
De toda la imagen, tomamos una muestra adecuada
para el procesado posterior: 50 píxeles de la parte
Player, que creará con un Manager, con la orden “Player
central de la imagen. La cifra escogida es un compromiso
player = Manager.createPlayer(String uriString);”. Con
entre la información de la imagen presente en la muestra
esto, podemos acceder a las imágenes de la cámara
y el tiempo que tardaremos en realizar el procesado.
como un flujo de video . Para tomar una fotografía,
usamos
el
método
VideoControl.getSnapshot(String
Sobre estos pixels vamos a ejecutar el algoritmo de
imageType), que nos devuelve un fotograma de ese flujo
custering
en el tamaño y el formato que especifiquemos en el
parámetro imageType.
El
dividir
clustering
un
o
conjunto
Cada cluster está representado por un centroide, que
viene a ser el promedio del cluster, por la varianza del
necesitamos acceder a los pixels. MIDP 2.0 ofrece
centroide, es decir, la dispersión de los elementos en un
directamente esta funcionalidad con el método getRGB()
cluster, y su número de elementos. El K-medias, es un
de la clase Image. Esta es la solución utilizada con el
algoritmo simple y rápido que trabaja con un número
teléfono Nokia 6600 en las aplicaciones que hemos
fijo de clusters, que en nuestra aplicación serán tres. Esto
implementado en este trabajo.
significa que podremos averiguar hasta tres colores de
El teléfono Nokia 3650 es MIDP 1.0 y no disponía de este
posible
en
modo que los elementos más parecidos estén juntos.
de esta imagen y realizar un procesado sobre ella,
Una
K-medias.
consiste
heterogéneo de elementos en grupos o clusters, de
Para que nuestra aplicación pueda obtener información
método.
llamado
agrupamiento
solución
era
el
una imagen simultáneamente.
método
Para implementar el algoritmo necesitamos definir la
“DirectGraphics.getPixels”, de la librería NokiaUI. Sin
distancia entre dos colores. Para esto, en primer lugar
embargo esta es un API propietaria y no se encuentra en
todos los terminales Java.
convertimos los valores RGB de los píxeles a coordenadas
La solución adoptada para el Nokia 3650 fue parsear el
adecuadas para comparar colores. La distancia entre dos
HSB (Crominancia, Brillo, saturación), que son más
fichero PNG. En este caso fue bastante sencillo, puesto
colores que hemos usado responde a la expresión:
que la información no estaba comprimida, y sólo
tuvimos que eliminar las cabeceras del fichero. En otros
d[(h1,s1,b1),(h2, s2,b2)]= α( h 1-h 2)+β( s 1-s 2)+γ( b1-b2)
terminales (por ejemplo, en el Nokia 6600) puede no
donde α, β y γ son coeficientes hallados empíricamente
darse
el
caso,
siendo
entonces
esta
tarea
muy
que representan la importancia de cada una de las tres
características a la hora de diferenciar dos colores.
28
Actas del II congreso javaHispano
El K-medias es un algoritmo iterativo que precisa una
Para detectar el movimiento, simplemente comparamos
condición de parada. En nuestro caso, el algoritmo se
el color del píxel central de una imagen con el de la
detendrá
dos
anterior. Dado existe cierto ruido en la imagen, aún en
condiciones: La primera es que se alcance un número
dos imágenes representando la misma escena los valores
máximo de operaciones, para evitar que el algoritmo se
exactos de los pixels cambiarán ligeramente. Esto
ejecute indefinidamente. La segunda es que la suma de
significa que para detectar el movimiento no basta con
las varianzas de los clusters deje de disminuir, lo que
ver si los píxeles son iguales. Lo que haremos será medir
significaría
la distancia Manhattan entre ellos y compararla con un
cuando
que
se
más
cumpla
cualquiera
iteraciones
no
de
mejoran
la
distribución de los elementos en los clusters.
umbral que fijaremos empíricamente. Notificaremos que
ha habido movimiento cuando este umbral se supere.
En el bloque de decisión vamos a determinar cuales son
los colores que contienen los clusters hallados. En primer
Para evitar falsas alarmas conviene tener un umbral
lugar, debemos averiguar si dos clusters contienen el
elevado, sin embargo esto tiene el inconveniente de que,
mismo color. Para esto, medimos la distancia entre sus
en el caso de que el objeto responsable del movimiento
centroides en relación con la varianza de ambos, y
sea del mismo color que el fondo, este movimiento
comparamos con un umbral hallado empíricamente.
pasará desapercibido. Para reducir este umbral sin
También debemos decidir si cada cluster contiene pixels
aumentar la probabilidad de falsa alarma, usaremos el
de un solo color o de varios. Para esto, compararemos
hecho de que el ruido es independiente: Cuando se
la varianza de los clusters con otro umbral. Con estas
produzca un movimiento, lo confirmaremos con los
comprobaciones,
colores
píxeles vecinos, y sólo lo notificaremos cuando el cambio
conforman la imagen, y si son más de tres, que es el
podemos
saber
cuántos
se halla producido para todos ellos. De esta forma, el
número de clusters, emitiremos un mensaje de error.
tiempo de proceso se mantiene reducido para la mayoría
de las iteraciones.
Después de esto, asignamos a cada centroide una
categoría de color. Para ello, hemos dividido el espacio
Realizando
HSB en regiones, cada una con un color asociado. Hecho
establecemos que con un umbral por debajo de 80,
esto, basta con ver en qué región cae el centroide de
sobre una distancia máxima entre pixels de 256·3, se
cada cluster.
producen falsas alarmas. En cuanto a la velocidad de
con
el
terminal Nokia
6600,
muestreo, es muy reducida. Utilizando el formato BMP,
Por último, tenemos que comunicar los resultados al
sólo conseguimos llegar a las 2 imágenes por segundo,
usuario. Cada región tiene asociado un fichero de audio
que es baja para aplicaciones con restricciones de tiempo
en que una voz pronuncia el nombre del color. Tras la
real en general, pero para este caso puede ser suficiente
etapa de decisión, los colores resultantes son emitidos.
si no nos encontramos ante cambios muy bruscos.
Los más abundantes van primero, de forma que el
usuario sepa el color dominante en la imagen.
4
pruebas
5
Detector de Movimiento
Pruebas de la cámara
En este apartado vamos a estudiar las imágenes
ofrecidas por la MMAPI en el terminal Nokia 6600, en
Esta aplicación muestrea continuamente el flujo de vídeo
términos de formatos, resolución, tamaño, número de
ofrecido por la MMAPI en busca de movimiento y,
colores, y tiempo de adquisición. Este teléfono, así como
cuando éste se produce, la aplicación emite un sonido y
la mayoría de los de su clase, tiene una cámara VGA,
muestra la imagen en que éste se produjo. Esta MIDlet
esto es, puede ofrecer fotografías de 640X480 pixels, y
simplemente compara una imagen con la anterior en un
esta es la resolución que podemos conseguir con la
bucle, y de éste si son distintas, sale del mismo.
aplicación nativa de la cámara y con programas en
La comparación entre dos imágenes es muy simple para
Symbian. Hemos hecho medidas de tiempo y tamaño
permitir que el bucle sea tan rápido como sea posible, y
por los tres formatos disponibles en el Nokia 6600, PNG,
que la velocidad esté limitada por la máxima frecuencia a
BMP y JPEG (esta información está disponible en la
la que la que podemos llamar al método getSnapshot().
variable
Por esta misma razón, esta velocidad de muestreo puede
defecto, el método getSnapshot() devuelve una imagen
no ser constante.
PNG de 160X120 pixels, pero se puede especificar el
de
sistema
video.snapshot.encodings).
Por
formato y las dimensiones en pixels deseados. Hemos
29
Actas del II congreso javaHispano
tomado medidas para cada tamaño y formato, y los
alcanza velocidades ligeramente superiores, del orden de
resultados se muestran en la Figura 1. También
siete imágenes por segundo.
comparamos la influencia de la complejidad de la
Las imágenes en JPEG son
imagen en el tamaño de fichero: Primero, tomamos una
tamaño de
imagen de una pared blanca, y luego otra de una escena
las más pequeñas, y el
fichero es poco dependiente de las
dimensiones de la imagen, y más de la complejidad de la
compleja, con gente y diferentes objetos. Los resultados
escena. Las imágenes PNG son mayores, pero es el único
se pueden ver el la Tabla 1.
formato obligatorio para las especificaciones de la
Tabla 1: Influencia de la complejidad de la escena en el
MMAPI. El formato BMP no usa compresión, por lo que
tamaño del fichero de imagen.
el tamaño de fichero es proporcional a las dimensiones
de la imagen. Sin embargo, la calidad de imagen es baja,
Tamaño (bytes)
PNG Simple
Compleja
BMP Simple
Compleja
JPEG Simple
Compleja
puesto que usa una paleta de 256 colores para (8 bits
28953
por pixel) para evitar que el tamaño se dispare. Hay que
44248
notar que para el tipo de aplicaciones que estudiamos, el
tamaño de fichero no es tan importante, ya que nosotros
20278
vamos a trabajar sobre los valores RGB de los pixels,
20278
luego en todos los casos necesitaremos un array de
1223
longitud dependiente de las dimensiones de la imagen.
Una vez tengamos este array, podemos liberar la
3469
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
Cuando el tamaño del fichero es demasiado grande para
elección.
el teléfono, lo que depende tanto del formato como de
las dimensiones de la imagen, hemos observado
que
18
pueden ocurrir dos cosas: En ocasiones, la aplicación se
16
bloquea, y la cámara deja de estar disponible hasta que
14
PNG
BMP
JPG
reiniciamos el teléfono. Más a menudo, la aplicación
12
TIME (sec.) ->
aborta con un mensaje tipo “Application closed Monty
Thread –7”.
Observando la calidad de las imágenes en diferentes
10
8
dimensiones, se aprecia que el teléfono siempre utiliza
6
imágenes del tamaño por defecto (160X120), y después
4
los reescala si es necesario. Por tanto, la calidad de la
2
imagen no mejorará.
0
160x120 (default)200x150
Para aplicaciones de tiempo real, tales como el Detector
de Movimiento, podemos ver que no se alcanza una
320x240
400x300
640x480
IMAGE DIMENSIONS ->
800x600
320x240
400x300
640x480
IMAGE DIMENSIONS ->
800x600
800
PNG
BMP
JPG
velocidad elevada: En el mejor de los casos, nos
700
acercamos a dos imágenes por segundo (para imágenes
600
del tamaño por defecto). Los formatos más rápidos son
FILE SIZE (KB) ->
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
500
400
300
200
(YCrCb) o imágenes comprimidas JPEG. De modo que la
máquina virtual sólo necesita tratar imágenes PNG o
100
BMP, las imágenes JPEG son creadas por hardware. Los
0
160x120 (default)200x150
mismos tests han sido realizados para el Nokia 3650 y
30
Actas del II congreso javaHispano
6.1
Figura 1: Tiempo de adquisición (arriba) y tamaño de
fichero (abajo) para diferentes tamaños en los formatos
Velocidad de operaciones
Primero mediremos la velocidad de operaciones básicas
de imagen disponibles.
del procesador, y podremos ver cuáles son más rápidas y
Algunos de los aspectos que hemos descubierto sobre el
cuáles deben ser evitadas al programar. Sólo nos
funcionamiento de la MMAPI de Java pueden explicarse
referimos a operaciones de bajo nivel: extracción de una
conociendo el acceso a la cámara en lenguaje nativo. En
variable
Symbian, el acceso está basado en imágenes, no en
desplazamientos lógicos, etcétera. Sólo hablaremos de
video. El viewfinder debe implementarlo el programador
este tipo de operaciones porque son las que hay
en
disponibles en J2ME.
cada
aplicación
concatenando
imágenes
periódicamente. Las imágenes se obtienen usando un
Para
esquema de objetos activos, y en un formato específico
de
medir
un
array,
tiempo,
suma
J2ME
de
ofrece
dos
el
variables,
método
System.currentTimeMillis(), que tiene una precisión de
de java, que posteriormente puede convertirse en el
milisegundos. Lo que haremos será repetir la operación a
formato deseado. Uno de los parámetros de la petición
medir en un bucle, restar el tiempo de un bucle vacío, y
de la imagen es la calidad, que puede ser alta o baja.
dividir
por
el
número
de
iteraciones.
Hemos
Una imagen de baja calidad (llamada snapshot), es
implementado un programa que realiza estas medidas y
QQVGA, es decir, de dimensiones 160X120 pixels, y de
muestra el resultado por pantalla. Las medidas estarán
4096 colores (12 bits por pixel). Una imagen de alta
distorsionadas por otros procesos concurrentes del
calidad es VGA (640X480) y de 16 millones de colores
teléfono, como la lectura de eventos de teclado u
(24 bits). Típicamente, las snapshots se usan para formar
operaciones relacionadas con el servicio telefónico. De
el viewfinder y video, y las imágenes VGA para la
hecho, si durante la ejecución del programa presionamos
fotografía propiamente dicha. Además, el programador
teclas repetidamente, se aprecia un incremento del
puede elegir entre dos perfiles de iluminación, noche y
tiempo. No intentaremos evitar estas distorsiones,
día, lo que modifica el brillo de la escena por medio del
simplemente tomaremos varias medidas y calcularemos
balance de blancos.
la media. Los resultados obtenidos se muestran en la
tabla 2.
Con esta información, podemos inferir que el MMAPI
crea el flujo de vídeo por medio de snapshots tomadas
Con estos resultados podemos inferir que la división
periódicamente, y los pasa a la aplicación. Las imágenes
debe ser evitada en la medida de lo posible, y que no
obtenidas con getSnapshot() son simplemente uno de
debemos abusar de la multiplicación, debiendo sustituir
estas snapshots, reescalada y con un formato diferente si
ambas por desplazamientos lógicos cuando sea posible.
es necesario. Por tanto no podremos acceder desde un
Vemos que, sorprendentemente, las comparaciones son
MIDlet a la calidad de imagen que la cámara puede
también lentas, incluso más que la multiplicación El
ofrecer.
acceso a una variable de un array es más lento que una
suma porque usa indirección.
6
Velocidad de operaciones y memoria
Hay que decir también que las operaciones deben usar
números enteros. Si es necesario utilizar decimales, lo
Para implementar aplicaciones de tratamiento de
adecuado es recurrir a la llamada aritmética de punto
imagen, nuestro terminal debe ser capaz de ejecutar
fijo, que permite cálculos decimales usando tipos
algoritmos pesados rápidamente, en ocasiones en
tiempo
real,
y
también
necesita
almacenar
enteros.
la
información de los píxeles de una o varias imágenes.
El teléfono Nokia 6600 utiliza un procesador ARM de 32
Según esto, la velocidad de las operaciones y la memoria
bits a 104 MHz, lo que hace un ciclo de reloj de
dinámica disponible son características claves
aproximadamente 10 nanosegundos. Típicamente, una
para
nuestros objetivos.
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.
31
Actas del II congreso javaHispano
Esto nos podría hacer pensar que, si las operaciones van
en las pruebas que acabamos de realizar en particular.
a la velocidad del procesador, entonces un MIDlet
También se da que los algoritmos de procesamiento de
correrá tan deprisa como una aplicación Symbian, lo cual
imagen son frecuentemente iterativos, con lo que la
no parece lógico. La explicación es que la máquina
suposición se cumplirá también para las aplicaciones
virtual del Nokia 6600, llamada Monty 1.0 VM, utiliza un
bajo estudio. Esto significa que podemos esperar un
esquema de compilación dinámica. Esto significa que la
buen comportamiento de nuestros MIDlets respecto a las
máquina virtual tiene, además de un interprete (que
aplicaciones nativas.
ejecuta bytecodes de Java), un compilador (que convierte
bytecodes en código nativo).
6.2
El código nativo es alrededor de un orden de magnitud
A continuación hablaremos sobre la memoria dinámica
más rápido que el interpretado, pero ocupa pero ocupa
más memoria. La Monty VM soluciona esto
de la que disponemos. La memoria volátil que se dedica
con un
al almacenamiento de objetos Java se denomina heap.
bloque más llamado Profiler, que identifica, en tiempo
Según las especificaciones, el Nokia 6600 dispone de una
de ejecución y mediante métodos estadísticos, partes del
heap de 3 Mbytes. Para comprobar esto, utilizamos una
código que el MIDlet ejecuta a menudo y repetidamente.
aplicación nativa llamada Fexplorer, que permite navegar
Estas partes del código se denominan hotspots. Cuando
por los archivos del teléfono, así como saber la memoria
el profiler identifica un hotspot, éste se compila de
libre del dispositivo. Con esta aplicación descubrimos
forma que las siguientes veces que el MIDlet llame a esta
que la memoria dinámica libre, independientemente de
parte del código se pueda ejecutar directamente en
los datos almacenados en la memoria flash, es de 10
código nativo. El resto del código, accedido menos a
Mbytes. Sin embargo, la heap podría ser menor al ser la
menudo, es ejecutado por el intérprete.
Operación
Memoria dinámica
memoria disponible para MIDlets.
Duración
Una operación
bucle (ms)
(ns)
Para
comprobar
implementamos
memoria
del
esto,
y
una
MIDlet
tamaño
que
tomar
que
se
le
medidas
intenta
reales,
reservar
especifique.
La
Bucle vacío
1 372.0
0.0
ejecutamos varias veces con tamaños crecientes, y vimos
Extracción de un
2 062.7
69.1
en qué punto aparecían excepciones del tipo Out of
Memory Error. Si la memoria se reserva nada más iniciar
array
la aplicación, alcanzábamos los 700 kilobytes. Sin
Incremento
1 573.3
embargo, si esta memoria se liberaba y se reservaba más
20.1
sin salir de la aplicación, y se incrementaba esta cantidad
(++)
Suma
1 565.9
19.4
Desplazamiento
1 562.5
19.1
poco a poco, alcanzábamos varios megabytes, por
encima de la heap indicada en las especificaciones del
teléfono.
lógico
Con estos experimentos, podemos concluir, primero, que
Multiplicación
la heap que puede alcanzar un MIDlet es de 10
1 862.6
49.1
12 396.7
1 102.5
asignada a un MIDlet es dinámica: inicialmente, la
Menor o igual
2 375.1
100.3
máquina virtual permite una pequeña cantidad, pero
Menor
2 351.4
97.9
Igual
2 554.8
118.3
División
Megabytes, y no de 3. Y segundo, que la memoria
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
Tabla 2: Duración de un bucle de 10 000 000 iteraciones
y de una sola operación. Promedio de diez medidas.
Una primera conclusión es que la primera acción a
La compilación dinámica se basa en la suposición de que
realizar al abordar una aplicación de este tipo, es
los programas ocupan la mayor parte del tiempo
ejecutando
una
pequeña
parte
del
código.
identificar los recursos de que disponemos desde J2ME,
Ésta
ya que pueden no ser los mismos que desde una
propiedad suele cumplirse con el software en general, y
32
Actas del II congreso javaHispano
aplicación nativa o que los que permitiría el hardware
MMAPI que permitan obtener el máximo provecho de las
del teléfono: que el terminal tenga cámara no significa
características de la cámara. Sin embargo, incluso con las
que sea accesible desde Java, y que ésta sea VGA no
capacidades de los terminales estudiados, pueden
significa que podamos sacar fotos de 640X480, etcétera.
implementarse aplicaciones novedosas y útiles mediante
un diseño cuidadoso y una buena dosis de creatividad.
De acuerdo con los resultados obtenidos, el límite mayor
lo impone la cámara, o más exactamente, las imágenes
Referencias
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
[1]
Especificaciones del terminal Nokia 6600. Forum Nokia
http://www.nokia.com/nokia/0,8764,33211,00.h
tml.
[2]
Especificaciones del terminal Nokia 3650. Forum Nokia
http://www.nokia.com/nokia/0,8764,2275,00.ht
ml.
[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.
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
33
Actas del II congreso javaHispano
34
Actas del II congreso javaHispano
Programación de dispositivos Bluetooth a través de Java
Alberto Gimeno Brieba
gimenete@gimenete.net
(OBject Exchange); se trata de un protocolo de alto nivel
Abstract
muy similar a HTTP.
En este documento se trata la programación de dispositivos
3
Bluetooth con Java mediante el API desarrollada por el JCP
y especificada en el JSR-82.
Primero abordaremos la programación de un cliente y
más tarde veremos cómo programar un servidor.
Keywords: Java, Bluetooth, J2ME, JSR-82, móviles.
1
3.1
Introducción
Bluetooth
es
una
El paquete javax.bluetooth
Clientes Bluetooth
Un cliente Bluetooth deberá realizar las siguientes
tecnología
de
comunicación
operaciones
inalámbrica, al igual que la tecnología Wi-Fi o los
para
comunicarse
con
un
servidor
Bluetooth:
infrarrojos. A diferencia de la primera, Bluetooth está
diseñada para dispositivos de bajo consumo y para
•
Búsqueda de dispositivos
conexiones de corta distancia (10 metros). A diferencia
•
Búsqueda de servicios
un mayor ancho de banda (hasta 11 Mbit/ segundo).
•
Establecimiento de la conexión
Bluetooth es, pues, una tecnología ideal para la conexión
•
Comunicación
de los infrarrojos, Bluetooth es omnidireccional y tiene
de dispositivos de bajas prestaciones (móviles, cámaras
El punto de partida es la clase LocalDevice que
de fotos, auriculares manos libres, impresoras,…).
representa el dispositivo en el que se está ejecutando la
aplicación. Este objeto es un singleton y se obtiene
Uno de los mayores ámbitos de utilización de Bluetooth
mediante
es sin duda los teléfonos móviles. Cada vez es más
LocalDevice.getLocalDevice().
Este
objeto
permite obtener información sobre el dispositivo: modo
común encontrar terminales móviles con soporte para
de conectividad, dirección bluetooth y nombre del
Java y Bluetooth y simplemente es un paso natural que
surja la necesidad de programar estos dispositivos a
dispositivo.
través de Java. Desde el JCP se ha desarrollado un JSR
El primer paso que debe realizar un cliente es realizar
que cubre esta necesidad. Se trata del JSR-82 que será
una búsqueda de dispositivos. Para ello deberemos
explicado en este documento.
obtener un objeto DiscoveryAgent. Este objeto es único y
se obtiene a través del objeto LocalDevice.
2
El JSR-82
DiscoveryAgent
programación de dispositivos Bluetooth. Depende de la
El objeto DiscoveryAgent nos va a permitir realizar y
configuración CLDC de J2ME, y se divide en dos
javax.bluetooth
y
javax.obex.
El
=
LocalDevice.getLocalDevice().getDiscoveryAgent();
El JSR-82[1] especifica un API de alto nivel para la
paquetes:
da
cancelar búsquedas de dispositivos y de servicios. Y
primer
también nos servirá para obtener listas de dispositivos ya
paquete provee la funcionalidad para la realización de
conocidos. Esto se lleva a cabo llamando al método
búsquedas de dispositivos, búsquedas de servicios y
retrieveDevices(). A este método se le debe pasar un
comunicación mediante flujos de datos (streams) o
argumento de tipo entero que puede ser:
arrays de bytes. Por otro lado el paquete javax.obex
permite la comunicación mediante el protocolo OBEX
35
Actas del II congreso javaHispano
•
•
DiscoveryAgent.PREKNOWN. Para obtener una
lista de dispositivos encontrados en búsquedas
•
DiscoveryAgent.CACHED. Para obtener una lista
•
El método retrieveDevices() devuelve un array de objetos
y
tiene
métodos
similares
una conexión cliente. El siguiente paso es realizar una
búsqueda de servicios. Antes de seguir deberemos
en el que se ejecuta la aplicación. Así pues, podemos
el
nombre
del
dispositivo
DiscoveryListener.INQUIRY_ERROR si se produjo
Ya hemos conseguido dar el primer paso para realizar
a
LocalDevice que, recordemos, representa al dispositivo
obtener
DiscoveryListener.INQUIRY_TERMINATED si la
un error en el proceso de búsqueda.
RemoteDevice. La clase RemoteDevice representa un
remoto
la
búsqueda ha sido cancelada manualmente o
de dispositivos “favoritos”.
dispositivo
si
búsqueda concluyó con normalidad,
anteriores.
•
DiscoveryListener.INQUIRY_COMPLETED
comprender ciertos conceptos.
mediante
getFriendlyName() y su dirección bluetooth mediante
Una aplicación cliente es una aplicación que requiere un
getBluetoothAddress().
servidor para que le ofrezca un servicio. Este servicio
puede ser: un servicio de impresión, un servicio de
Podríamos omitir la búsqueda de dispositivos y pasar
videoconferencia,
directamente a la búsqueda de servicios en caso de que
un
servicio
de
transferencia
de
archivos, etc. En una comunicación TCP-IP un cliente se
deseásemos conectar con alguno de los dispositivos
conecta directamente a un servidor del que conoce el
pertenecientes a alguna de estas listas. Sin embargo lo
servicio que ofrece, es decir, conocemos a priori la
más común será intentar conectar con un dispositivo
localización del servidor y el servicio que nos ofrecerá;
encontrado en una búsqueda de dispositivos, debido a
sin embargo un cliente Bluetooth no conoce de
que obviamente lo tendremos a nuestro alcance.
antemano qué dispositivos tiene a su alcance ni cuáles
Una búsqueda de dispositivos se inicia llamando al
de ellos pueden ofrecerle el servicio que necesita. De
método
un
modo que un cliente Bluetooth necesita primero buscar
argumento de tipo DiscoveryListener. DiscoveryListener
los dispositivos que tiene a su alcance y posteriormente
es
nuestra
les preguntará si ofrecen el servicio en el que está
conveniencia y que será usada para que el dispositivo
interesado. Este último proceso se denomina búsqueda
notifique eventos a la aplicación cada vez que se
de servicios y es el siguiente paso que un cliente debe
descubre un dispositivo, un servicio, o se finaliza una
realizar.
una
startInquiry().
interfaz
que
Este
método
requiere
implementaremos a
búsqueda. Estos son los cuatro métodos de la interfaz
Cada servicio es identificado numéricamente. Es decir, a
DiscoveryListener:
•
deviceDiscovered()
•
inquiryCompleted()
•
servicesDiscovered()
•
serviceSearchCompleted()
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
Los dos primeros métodos son llamados en el proceso
(color, blanco y negro), etc. Los atributos también están
de búsqueda de dispositivos. Los otros dos son llamados
identificados numéricamente, es decir, para referirnos a
en procesos de búsqueda de servicios.
un atributo usaremos su número asociado.
Cada vez que un dispositivo es encontrado se llama al
Las búsquedas de dispositivos también se realizan
método deviceDiscovered() pasando un argumento de
mediante el objeto DiscoveryAgent. Concretamente
tipo RemoteDevice.
usaremos
el
método
searchServices()
al
que
le
tendremos que pasar un objeto DiscoveryListener que
Una vez que la búsqueda de dispositivos ha concluido se
recibirá los eventos de la búsqueda, el dispositivo en el
llama al método inquiryCompleted() pasando como
que realizar la búsqueda (un objeto RemoteDevice que
argumento un entero que indica el motivo de la
finalización. Este entero puede valer:
normalmente
obtendremos
en
la
búsqueda
dispositivos),
los
en
los
que
servicios
de
estamos
interesados, y los atributos que queremos conocer sobre
36
Actas del II congreso javaHispano
dichos servicios (tipo de papel, tipo de tinta, etc). Por
open() y le pasaremos una URL que contendrá los datos
ejemplo un cliente que esté interesado en un servicio de
necesarios para realizar la conexión.
impresión, para imprimir un texto probablemente sólo le
No necesitaremos construir la URL a mano ya que el
interese conocer el tipo de papel, sin embargo si
objeto ServiceRecord posee un método que nos ahorra
queremos imprimir una imagen estaremos también
esta tarea: getConnectionURL().
interesados en si soporta o no tinta de color.
Llegados a este punto debemos saber que tenemos dos
Si se encuentra algún servicio se nos notificará a través
del
objeto
DiscoveryListener
mediante
el
formas diferentes de comunicación: a través de flujos de
método
datos utilizando el protocolo SPP (Serial Port Profile) , o
servicesDiscovered(). Se nos pasará un array de objetos
bien a través de L2CAP enviando y recibiendo arrays de
ServiceRecord que encapsulan los atributos de servicio
bytes. La forma más sencilla es mediante SPP.
que solicitamos al invocar la búsqueda. Los valores de
estos atributos de servicio son objetos DataElement.
Si el servidor utiliza SPP el método Connector.open() nos
devolverá
Un objeto DataElement encapsula los tipos de datos en
un
objeto
de
tipo
javax.microedition.io.StreamConnection. A través de
los que puede ser representado un atributo de servicio.
este objeto podemos obtener un (Data)InputStream y un
Estos pueden ser: números enteros de diferente longitud
(Data)OutputStream. Por lo tanto ya tenemos un flujo
con o sin signo, cadenas de texto, URLs, booleanos, o
de lectura y un flujo de escritura por lo que estamso en
colecciones de DataElements.
condiciones de leer y escribir datos.
Un ServiceRecord es, pues, como una tabla que
En caso de que el servidor utilice L2CAP el método
relaciona los identificadores de los atributos con sus
Connector.open() nos devolverá un objeto del tipo
valores (objetos DataElement).
javax.bluetooth.L2CAPConnection.
Con
este
objeto
Cuando finalice la búsqueda de servicios se nos
leeremos bytes con receive() y escribiremos bytes con
notificará
send().
mediante
una
serviceSearchCompleted()
llamada
de
al
método
la
interfaz
DiscoveryListener. Se nos pasará un argumento de tipo
3.2
entero indicando el motivo de la finalización. Este
La creación de un servidor Bluetooth es más sencilla que
entero puede valer:
•
la programación de un cliente ya que no necesitamos
SERVICE_SEARCH_COMPLETED: la búsqueda ha
realizar ningún tipo de búsqueda. Concretamente los
finalizado con normalidad.
•
•
pasos que debe realizar un servidor Bluetooth son los
siguientes:
SERVICE_SEARCH_TERMINATED: la búsqueda
ha sido cancelada manualmente.
•
Crear una conexión servidora
SERVICE_SEARCH_NO_RECORDS: no existe la
•
Especificar los atributos de servicio
•
Abrir las conexiones cliente
información solicitada.
•
SERVICE_SEARCH_ERROR: finalizó por un error.
•
SERVICE_SEARCH_DEVICE_NOT_REACHABLE: el
Crear la conexión servidora es relativamente simple.
Sencillamente
dispositivo no está a nuestro alcance.
Estas
Servidores Bluetooth
constantes
son
miembros
de
debemos
llamar
al
método
Connector.open() pasándole una URL con una sintaxis
la
determinada. En caso de querer comunicarnos mediante
interfaz
DiscoveryListener.
SPP la URL comenzará por “btspp://” y en caso de querer
Si hemos encontrado algún servicio que nos interesa
“btl2cap://”.
comunicarnos mediante L2CAP la URL comenzará por
pasaremos al siguiente paso: abrir la conexión.
“localhost/”
CLDC:
a
javax.microedition.Connector.
través
de
Usaremos
la
su
host.
Esto
deberemos
determina
indicar
que
no
servidores. Seguidamente sólo nos queda concatenar a
misma forma que se abre cualquier otro tipo de
en
como
continuación
queremos conectarnos a nadie, sino que queremos ser
Abrir una conexión Bluetooth se lleva a cabo de la
conexión
A
la URL el identificador del servicio (UUID) que vamos a
clase
ofrecer.
método
37
Actas del II congreso javaHispano
•
A continuación llamaremos al método Connector.open()
pasando la URL como argumento. Si la URL comienza
DISCONNECT. Usado para finalizar la sesión.
Las cabeceras de un mensaje OBEX son encapsuladas por
por “btspp://” nos devolverá un objeto del tipo
un objeto HeaderSet. Existen cabeceras de uso común
javax.microedition.StreamConnectionNotifier y en caso
como COUNT, NAME, LENGTH,… Sin embargo podremos
de que la URL comience por “btl2cap://” nos devolverá
crear cabeceras personalizadas.
un objeto javax.bluetooth.L2CAPConnectionNotifier.
La clase Operation provee la funcionalidad para leer y
El siguiente paso es especificar los atributos de servicio.
enviar mensajes que no sólo tienen cabeceras sino que
Por ejemplo si vamos a ofrecer un hipotético servicio de
también tienen un cuerpo de mensaje. Esta clase permite
impresión podríamos indicar qué tipo de papel y de tinta
obtener un (Data)InputStream y un (Data)OutputStream
ofrecemos. Los atributos de servicio se almacenan en un
para leer o escribir el cuerpo del mensaje.
objeto ServiceRecord. Cada conexión servidora tiene un
ServiceRecord asociado que se obtiene a través del
Ahora que conocemos las clases básicas pasemos a ver
LocalDevice.
cómo programar un cliente OBEX.
Establecer
los
atributos
de
servicio
es
sencillo,
simplemente tenemos que crear objetos DataElement y
4.1
añadirlos al ServiceRecord.
La programación de un cliente OBEX es relativamente
Una vez establecidos los atributos de servicio ya estamos
simple. Debemos abrir la conexión, como siempre en
CLDC con el objeto Connector. Deberemos pasarle una
en condiciones de escuchar y procesar las conexiones
URL que comience por “irdaobex://” y nos devolverá un
cliente. Para ello usaremos el método acceptAndOpen().
objeto de tipo javax.obex.ClientSession. Lo primero que
En una conexión servidora SPP este método devuelve un
deberemos hacer será ejecutar el método connect() para
javax.microedition.StreamConnection, y en una conexión
servidora
L2CAP
devuelve
un
objeto
del
Un cliente OBEX
iniciar la sesión.
tipo
javax.bluetooth.L2CAPConnection. En este punto ya
A partir de aquí ya podemos realizar peticiones al
podemos leer y escribir datos del mismo modo que lo
servidor a través de los métodos put(), delete(), get() y
hace un cliente.
setPath(). Todos los métodos requieren un objeto
HeaderSet como parámetro. Los métodos put() y get()
4
El paquete javax.obex
adicionalmente devuelven un objeto Operation que
permite
El paquete javax.obex permite manejar el protocolo de
escribir
o
leer
el
cuerpo
del
mensaje
respectivamente.
alto nivel OBEX (OBject Exchange). Se trata de un
protocolo muy similar a HTTP. Al igual que este último,
Para cerrar la sesión llamaremos al método disconnect().
OBEX se basa en mensajes compuestos por cabeceras de
mensaje y opcionalmente de un cuerpo de mensaje.
4.2
Adicionalmente los mensajes de respuesta del servidor
Un servidor OBEX
poseen un código de respuesta indicando éxito o error.
Crear una conexión servidora OBEX es también muy
Al igual que en HTTP, los mensajes de petición del cliente
llamando al método Connector.open(). La URL debe
simple. Lo primero de todo es crear un SessionNotifier
al servidor en OBEX se clasifican por métodos. Estos son
comenzar por “irdaobex://localhost”. Ahora simplemente
los métodos que existen.
escucharemos las conexiones cliente llamando al método
•
CONNECT. Inicia la sesión.
acceptAndOpen(). Este método requiere un argumento
•
PUT. Envía un archivo al servidor.
es un objeto que deberemos implementar nosotros. Se
•
GET. Solicita un archivo al servidor.
implementa de forma muy similar a un servlet: por cada
•
DELETE. Solicita la eliminación de un archivo.
que se le pasan los datos de la petición. Así pues
•
SETPATH. El cliente desea cambiar el directorio
de tipo ServerRequestHandler. El ServerRequestHandler
método del protocolo OBEX tiene un método asociado al
tenemos los métodos onConnect(), onGet(), onPut(),
onDelete() y onDisconnect(). Todos los métodos tienen
actual dentro del sistema de archivos del
como argumento un objeto HeaderSet que encapsula las
servidor.
cabeceras de los mensajes, exceptuando los métodos
38
Actas del II congreso javaHispano
onPut() y onGet() que requieren un cuerpo de mensaje y
de carrera. Pero sobre todo a todos los miembros de
por ello su argumento es de tipo Operation.
javaHispano por hacer esto posible.
Adicionalmente todos los métodos a excepción de
Referencias
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
39
[1]
Especificación del JSR-82: Bluetooth
http://jcp.org/en/jsr/detail?id=82.
desde
Java.
[2]
Alberto Gimeno Brieba. JSR-82: Bluetooth desde Java.
http://www.javahispano.org/tutorials.item.action?id=49.
Actas del II congreso javaHispano
40
Actas del II congreso javaHispano
! "
#
"
"
*
)
$
6
"%
"
&
"
& '
*
'
/3
.
#
(
"
#
"
$
"
"
"
&
&
"
&
"
.
&
#
*
* '
'
*
'
*
/3
&
# %
"
'
&
.
35
"
'
'
'
*
&
$
&
.
&
&
-*
%
. + 8
'
'3
' $
'
5
"
*
$
*
'$
-
"
"
&
"
"
'
'
7
*
-
-
1 #2
4
-
#
&
#
/)+0$
-
%
#
'
&
'
&
-
'
'
#
*
,
.+
7
#
+
(
"
*
&
(
,
,
&
*
&
)
#
41
.
+
9
Actas del II congreso javaHispano
% #
*
. +
"6
53:
"
*
.
#
&
'
'
.
,
%
(
&
(
*
& %
.
(
*
;
)
"%
+
%
2
'
&
"
" '
#
"
*
&
*
(
&
*
"
.
*
"
/3
. &
3
+
"
&
#
*
"
(
.
#
"
53:
&
%
#'
(
'
&
* #
*
.
&
#
>
&
*
"
(
.
"
9 +
"
'
*
*
&
6
#
*
9 +
+
+
*
&
*
*
&
&
"
*
' "
9 +
'
"
#
.
$
3"
#
+
'
2
&
*
&
"
#
"
"
"
((.<: '
(
.
#
&
*
"
&
(
#
'
"
#
2
#
= #&
#
,
&
*
-
,
*
%
#
(
*
'
'#
&
&
&
*
"
&
(
*
,
42
'
.
Actas del II congreso javaHispano
&
"
2
"
#
"#
2
&
(
"
G
"
&
"
&
#
%
-
"
#
"
"
"#
2
'
2
"
" " F &
'
"
)
'"
E
>
&
#7
3
#
2
%
"
!
-
finalize() 2
&
#
# #
'
?
"
"
#
H4I
"%
.
&
'
#
&
&
'
*
&
#
"
"%
#
"
=
&
" %
&
(
#
2
"
'
#
&
* H;I
.
.
&
*
+
&
"
'
&
&
(
#
#
6
&
. +
#
<
C
*"
>
&
&
'
'
-
'
'$
*
. +3
6
%
%
#&
"
(
@.
&
3
A.
,
"
*
,
A.
#
"
%
C
'
*
"
.
&
"
"
&
&
*
"
%
*
&
&
;44
/
5
"
BC1
3
"
&
&
#
6
@
(
&
#
*
:&
"
'
*
#
&
<
"
"
&
-
%
'
6
'
&
,
3
D!
(
*
; ; 4'
*
.
43
&
'
Actas del II congreso javaHispano
%
'
'
$
&
&
&
&
@
"
A
&
&
"
&
&
3
&
# JKL
'
-
"
%
(
%
*
;;4
#
&
&
"
"
&
>
#
.
#"
*
#
#
"
(
&
'
)
*
#
"
"
7
'
*
'
"
#
"
&
'
*
&
"
.
*
35
(
"
#
$
,
&
-
&
"
&
'
"
= #&
'
&
-
&
%
#
#
"
&
6
*
>'
'
,
3 &
(
N
"
*
N
*
3
"
"
"% :7
4
"
8:
7
#
&
%
9&
(
:7
#
. +3
* '#
/3 '/.<3
*
+ 73
=
*
@=
&
<
'
'
"
&
"
M
&
#
A
%
"
"
&
"
&
*
'
#
&
<: '((.<:
$ <
(
"
#
&
&
#
"
&
&
+
'
&
*
"
%
&
<
BC 1
'
'
&
"
#
((.<:
<
*
:7
&
2
"
"
44
'
#
&
(
#
7
&
4
#<
3
#'
*
# C1
<
Actas del II congreso javaHispano
C 3
* &
M
&
*
+
#
$ 6
# &
&
&
&
&
#
*
$ "
#
&
(
3
&
"
"
)
"
#
" '
'
&
,
*
(
"
*
'
((.<:
#
(
.
&
'
*
&
&
&
&
*
&
"
&
"
*
"
*
7
"
K)
"
,
(
"
*
*
"
#
.
-
#
"
#
&
'
$
%
*
"
#
'
#
"
*
&
"6
"
"
5 9#
#
$
*
5
&
,
&
&
&
"
"
&
.
&
(
&
#
#
"
&
'
"
%
$
*
#
&
*
'
.
"
&
,
&
*
&
'
"
&
(
&
"
*
&
"
'
*
(
"
&
"
"
&
"
#
*
%
"
8
%
&
2
#
#
&
#
)
*
"
&
*
&
(
*
$
"
*
2
'
&
*
%
# .
*
*
"
"
&
7
"
'&
(
"6
#
&
"
#
'
*
"
"
&
&
* '
(
+
"
+
45
#
"
Actas del II congreso javaHispano
(
#
B
<O
#
B
:
#
+ -
(
*
"
:
&
"
,
#
#
#
"
%
*
"
:
%
J(
#
*
&
#
5
.5&
&
-
+
&
(
'
.
859
#
&
*
&
+
5
'
&
'
B .5
*
3*
'
.
"
"
4
5
*
#
*
*
"
#
#
(
#
"
"
#
#
-
3
&
"
!
*
; 5
$
N
&
'
"
'#
*
' +
'
"
#
(
((.<:
%
&
&
#
"
.
-
&
#
-
#
(
&
"
&
. +3 &
'
*
"
#
#
&
#
#
7
*
'
#
"
"
&
"
. +3
&
# "
.
C :
%
*
#"
2 '
'
#
&
"
#
K :
'
'
6
'
'
'
#
'
%
7
%
' E
'
(
"
5
"
. +
'
? 5
&
'#
#
#
46
&
"
#
Actas del II congreso javaHispano
&
&
&
(
&
*
"
"
.
"
&
"
"
*
&
"
9 .
#
.5
. +
&
,
*
(
"
$ 6
&
9 .
&
"
'&
&
*
#
"
*
&
9 Q
*
;C
,
#
.
"
'
'
#
.
*
&
#
7
"
*
+3 7C 8+
E 9 (
6
*
+
. + '
*
'
&
6
R"
"
#
3
R,
, S
S'R
S# R
S&
.
&
'
%'
'
'
*
#
"
*
&
.
6
(
. +
"
-
'
&
"
"
#
,
-
@> &
A
%
&
.
*
#
. + '
(
.
#
'
&
/)+ 0 $
5
-&
'
'
'
+
#
!
&
'
;'
"
(
&
&
&
"
,
*
*
35
*
#
&
%
"
.
((.<:
"
"
"0
*
00222
#
(
. 3 $
00
$
&
#
"
.
*
M
*
&
?
" '
'
&
*
;
,
4L .
*
"
&
*
. 3
P(
3
&
&
* &
$
+3 7
#
.
. 3
#
*
,
?
&
"
*
&
%
2
. 3
E"
+3 7
C
35 7
0
47
E
371
Actas del II congreso javaHispano
.
'
&
&
' #'
#
'
%
*
'
*
"
*
&
*
#
3
7
7
E
8+3 79
M
K
35
?/.. 8
!"#
$ %
.
'
/)+ 0 $
!+3(B
*
-
#
. 3
!
'
&
*
,
&
%
*
"
&
&
&
(
# <
>
%
"6
%
<
4G4L
"
<
 ;4M
H4I
;;44
"N

H;I
%
K
C'
.
F/
"
;
?/.. 7< ?4 P4P ;/0?/
2
B
3
!+3( "
T
.5
E "
!
#
+
3
#
-
&
00
*
"
0
48
Actas del II congreso javaHispano
JVMTI, creación avanzada de profilers de aplicaciones con
la nueva API de Tiger
Daniel Glez-Peña
Florentino Fdez-Riverola
lipido@gsid.ei.uvigo.es
riverola@uvigo.es
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.
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.
1.1
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.
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.
Keywords: Java Virtual Machine Tool Interface, Java
Virtual Machine Profiler Interface, Java Virtual Machine
Debug Interface, JavaTraceIt!.
1
JVMPI y JVMDI
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.
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
Por otro lado, un profiler se puede definir como una
utilidad que analiza el rendimiento de un programa con
49
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
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:
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:
•
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
Class File Load Hook
Class Load
Class Prepare
Compiled Method Load
Compiled Method Unload
Data Dump Request
Dynamic Code Generated
Exception
Exception catch
Field Acess
Field Modification
Frame Pop
GC Finish
50
Method Entry
Method Exit
Monitor Contended
Enter
Monitor Contended Exit
Monitor Wait
Monitor Waited
Native Method Bind
Object Free
Single Step
Thread End
VM Death
VM Initialiation
VM Object Allocation
VM Start
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
Threads
Grupos de threads
Stack Frame
Montón (Heap)
Variables locales
Puntos de ruptura
(Breakpoints)
Seguimiento de
variables (Watches)
Clases
Objetos
Atributos (Fields)
Métodos
Monitores
Intercepción de
funciones JNI
Gestión de eventos
Capacidades
(Capability)
Reserva y liberación de
memoria. No se deben usar
funciones tipo malloc.
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.
Obtener información de los
grupos de threads
Obtener información de los
registros de activación
contenidos en la pila de
cada hilo.
Recorrer el montón
llegando a los objetos.
Posibilidad de invocar al
recolector de basura.
Acceder a las variables
locales para lectura y/o
modificación.
Gestión de los puntos de
ruptura. Orientado
totalmente a depuración.
Seguimiento de una
variable, para detectar
cuando se lee o se modifica.
Información completa
acerca de las clases, además
de la posibilidad de
modificarlas (ver sección 4).
Información básica de un
objeto: hash code, tamaño
y uso de su monitor.
Información acerca de los
atributos (fields) de las
clases.
Información acerca de los
métodos de las clases.
Manejo de monitores para
evitar problemas de
exclusión mutua, sobre
todo en el acceso a la
información que recolecta el
agente.
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.
Establecimiento de qué
Temporizadores
System Properties
General
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.
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.
Utilidades para medir los
tiempos de CPU usados por
los distintos hilos. La
temporización es muy
utilizada en profiling.
Obtener información acerca
de la JVM usada.
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:
51
•
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
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;
3.3
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:
/* obtener el entorno JVMTI */
vm->GetEnv( (void **)&jvmti, JVMTI_VERSION);
/* exigir capacidades */
jvmti->GetCapabilities( &capabilities);
capabilities.can_generate_all_class_hook_eve
nts = 1;
jvmti->AddCapabilities( &capabilities);
>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):
/* 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));
>LD_LIBRARY_PATH=.
>java –cp . –agentlib:agent Aplicacion
/* 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);
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.
return JNI_OK;
}
3.2
Compilación y ejecución del agente
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.
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.
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.
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.
/* 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);
52
Actas del II congreso javaHispano
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 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.
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:
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
•
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.
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
53
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.
Figura 5: El profiler de JavaTraceIt!.
La Figura 5 muestra una captura de JavaTraceIt! y de su
profiler en ejecución.
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:
54
•
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
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.
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:
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.
public class Tracker {
/* Para contar el numero de instancias se
necesita capturar la creacion de objetos y
de arrays.*/
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.
/* Al principio de
java.jang.Object.<init>(), se inyecta una
llamada a Tracker.ObjectInit().*/
private static native void
nativeObjectInit(Object thr, Object obj);
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:
•
•
•
public static void ObjectInit(Object obj)
{
…
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.
nativeObjectInit(Thread.currentThread(),
obj);
…
}
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.
/* Inmediatamente despues del bytecode
newarray, se inyecta una llamada a
Tracker.NewArray(). */
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.
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.
La migración de JVMPI_EVENT_CLASS_LOAD no ha
supuesto ningún problema ya que existe su equivalente
en JVMTI.
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.
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.
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
55
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/Programmi
ng/jvmti/
[4]
Kelly O’Hair. The JVMPI Transition to JVMTI.
http://java.sun.com/developer/technicalArticles/Programmi
ng/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://wwwplan.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.ejtechnologies.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_d
epurador_y_optimizador.pdf
56
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
jmarranz@eresmas.com
jmarranz@dii.etsii.upm.es
Pero no nos engañemos, Java al igual que la plataforma
Abstract
LAMP
complejas
y
diversas
que
en
el
servidor,
su
relevancia
fundamentalmente
de bases de datos. Este papel muy relevante en el Web
las
aplicaciones normalmente necesitan acceder directamente a
se debe a varios factores entre otros:
recursos hardware o servicios del sistema operativo no
1)
necesariamente cubiertos por el Java estándar, con los que
plataformas Unix han tenido un gran papel al ofrecer
mayor familiaridad para el usuario. Este problema ha sido
tradicionalmente
resuelto por Java programando con lenguajes nativos
los
desarrolladores
de Java
no
conocen
potencia
y
robustez.
Y
siguen
teniéndolo gracias en parte a Java y a la explosión de
usando el complejo JNI y necesitando un
servicios y comercio electrónico basados en Web que nos
compilador o un IDE. La realidad muestra que buena parte
de
La portabilidad de Java entre sistemas
En un mundo, el del servidor, en donde Linux y otras
se consigue una mayor integración con el sistema y una
(C/C++)
en
aplicaciones basadas en Web y especialmente en gestión
Las necesidades en el desktop son habitualmente mucho
más
tiene
trajo la burbuja tecnológica. El papel de JDBC ha sido
C/C++.
fundamental permitiendo una conectividad con bases de
JNIEasy[1] es una herramienta que permite la interacción
datos más estandarizada y portable que las soluciones
con librerías nativas (DLLs) para acceder directamente
desde Java a recursos del S.O. o a hardware especializado
basadas en ODBC, y OleDB.
sin necesidad de programar con JNI, C o C++. Los
2)
La portabilidad de las tecnologías Web y la casi
programas desarrollados con JNIEasy serán 100% Java,
independencia tecnológica entre el cliente y el
pudiendo llamar desde Java a métodos nativos contenidos
servidor
en DLLs, exponer automáticamente métodos de clases
normales a llamadas desde código nativo (callbacks), definir
Por ejemplo, nada impide que Java en un servidor no
“estructuras nativas” como simples clases, y gestionar la
Windows
produzca
HTML
transmitido
por
“memoria nativa” de forma automática con el garbage
consumido en Windows por el Internet Explorer.
collector. Las soluciones existentes hasta ahora no han
3)
La
calidad,
fiabilidad,
seguridad,
HTTP
robustez
y
conseguido una solución tan transparente y céntrica en
capacidad de gestión de la complejidad que ofrecía
Java, gracias a la Aspect Oriented Programming y el
Java como plataforma frente a soluciones más
bytecode enhancement.
“amateur” como ASP o PHP, o frente a la
inseguridad y complejidad que ofrece C/C++ poco
Keywords: Java, JNI, AOP, bytecode enhancement, C,
C++, DLL, transparencia
apto para el mundo esencialmente “concurrente”
que exige el Web.
1 El dominio casi absoluto de las
tecnologías Windows en el desktop
4)
subyacentes a Internet (http, applets, RMI etc)
De todos es sabido la enorme penetración que tiene Java
5)
en el mundo del software, Java es sin duda una de las
junto
con
.Net
y
La aparición de una pléyade de frameworks
orientados
tres plataformas relevantes de desarrollo software
actualmente
La “familiaridad” de Java con las tecnologías
fundamentalmente
a
simplificar
el
desarrollo Web y la manipulación de bases de datos,
LAMP
desde los estandarizados (J2EE=JSP+EJB, JSF, JDO)
(Linux+Apache+MySQL+Perl/PHP).
con
57
versiones
libres
y
comerciales,
hasta
los
Actas del II congreso javaHispano
populares de código abierto como Struts, Hibernate,
de pastel al mundo Microsoft/Intel (aunque ahora el reto
Spring etc.
también está contra Linux/Intel).
Sin embargo todo cambia cuando lo vemos desde el
El WORA es un hecho en el lado del servidor, pero está
punto de vista de los sistemas orientados a ser usados
todavía lejos de conseguirse en el desktop. El terreno del
como puesto de trabajo individual es decir el llamado
desktop está lleno de “piedrecitas” en donde una
desktop o escritorio.
solución relativamente sencilla en C, C++, Visual Basic ¡y
ahora en .Net!, puede ser un verdadero “pain in the ass”
Varios hechos:
1)
en Java, cuando ha de accederse directamente al sistema
Windows está instalado en más
operativo o al hardware, y no siempre estamos hablando
del 90% de los
de necesidades de alto rendimiento que justifiquen JNI.
computadores del mundo [2]
2)
3)
Windows
En este sentido Java está hoy día en una encrucijada: o
orientadas al desktop están desarrolladas con
conquista un aceptable territorio en el desktop o puede
tecnologías Microsoft (Visual C++, Visual Basic)
perder definitivamente esa batalla (como la perdió
sean aplicaciones de Microsoft o no.
Borland con C++ y Delphi), en la medida en que .Net es
La
gran
Windows
mayoría
está
de
aplicaciones
fuertemente
un competidor directo de Java, obviamente se integra
componentizado,
muy bien con Windows, no es un juguete para amateurs
normalmente a través de dichos componentes
como en cierto modo era Visual Basic, ni tan complejo e
accedemos a los recursos del hardware o a los
inseguro como era el Visual C++.
servicios del sistema operativo.
4)
En esta guerra hay muchos factores, ciertamente se
La API primaria con la que Windows se “expone” es
necesita mucho más WORA pero quizás también una
C (Platform SDK), las demás son capas sobre ésta
visión más pragmática y menos exigente a corto plazo:
(incluido el COM). El SDK C es gratuito.
5)
más “Java for Windows only”, huyendo de la “palabra
Los drivers propietarios que acceden a los recursos
maldita” que hace inclinar la balanza por el universo
del hardware exponen prácticamente siempre una
Microsoft: JNI
interfaz C o COM.
Java ha hecho un gran esfuerzo por ofrecer una “capa”
3
Java
La programación en lenguajes nativos es más compleja
para
cualquier
necesidad
permitiendo
una
integración portable con el S.O., pero la experiencia dice
JNI amigo y enemigo
que con Java y menos robusta, JNI es relativamente
que no siempre es posible “esperar” que Sun (o en
complejo como mezcla de dos mundos (Java y nativo)
general el ecosistema Java) lo haga, pues obviamente
pues supone programar “en Java” pero con C/C++.
Microsoft siempre irá delante en sus propias tecnologías.
Cuando se realiza una aplicación Java con JNI siempre
Esfuerzos como el JDIC[3] o el JMF[4] son encomiables,
existe la lucha entre si más Java o más C/C++, el
pero en el caso del JMF, un componente tan básico,
modelar dos veces, la conversión de datos etc. De hecho
todavía no tiene lugar en el JRE y su licencia es todavía
no es raro que el resultado sea una aplicación basada en
demasiado restrictiva.
código nativo fundamentalmente y una fina capa Java.
De todas formas existen infinidad de casos no típicos,
El problema no es el JNI en sí mismo, JNI tiene el
normalmente acceso a hardware propietario, en donde
importantísimo papel de no permitir que Java sea una
es difícil esperar una solución estándar, ni siquiera del
plataforma cerrada. En algunas aplicaciones en donde se
propio fabricante, el “háztelo tu mismo si puedes” es la
necesita una comunicación íntima con el hardware con
regla.
alto rendimiento es insustituible, pero es sin duda una
de las grandes piedras que se encuentra Java en el
2
WORA, realidad y utopía
desktop: cuando es la única alternativa para problemas
que no resuelve Java (es decir, que otros todavía no han
El WORA (Write Once Run Anywhere) es la utopía
resuelto con JNI).
deseada por Sun (y competidores en el mismo “lado”)
Ejemplo
para poder vender más hardware y arrebatar un trozo
ilustrativo:
Sourceforge.net,
el
inmenso
repositorio de aplicaciones de código abierto, Java goza
58
Actas del II congreso javaHispano
de muy buena salud (ver Tabla 1, muchos de los
El bytecode enhancement es AOP en su sentido más
proyectos es sabido que combinan C y C++ y el propio
primitivo, consiste en la introducción de código nuevo
Java por lo que no son “sumables”).
Java, precompilado, directamente en las clases a nivel de
bytecode, así como la modificación de código ya
Tabla 1: Lenguajes en Sourceforge
Lenguaje
Proyectos
Java
13274
C
C++
Visual Basic
13807
14117
1977
C#
1976
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
Sin embargo filtremos la categoría: Multimedia / Vídeo y
multitud de puntos del programa de forma fuertemente
con combinaciones de lenguajes entre Java, C y C++
intrusiva.
(Fig. 1).
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
Figura 1: Sourceforge, lenguajes en proyectos de vídeo
(pointcuts) dentro del conjunto de puntos de
(noviembre de 2004)
unión posibles (joinpoints)
Tabla 2
El conjunto de nuevas funciones (advices), atributos y
poincuts orientados a realizar una cierta tarea es lo que
Lenguaje
Proyectos
Java sin C o C++
10
se denomina en AOP aspecto.
Java con C o C++
13
En JNIEasy no se utiliza ningún framework AOP concreto,
C o C++ sin Java
87
sino que se utiliza directamente bytecode enhancement,
la razón hay que buscarla en la gran libertad de
De acuerdo con la Tabla 2 podemos concluir que Java no
manipulación que permite respecto a usar un framework
es muy relevante en áreas como la manipulación de
concreto, pues todo framework al mismo tiempo que
vídeo, tarea típica de desktop, y lo normal es que venga
supone una formalización elegante de un servicio,
acompañado de programación en lenguajes nativos (JNI
supone al mismo tiempo la introducción de limitaciones,
con gran probabilidad).
la analogía hay que encontrarla por ejemplo entre
programar en C o en ensamblador. De todas formas no
4 Aspect Oriented Programming y el
bytecode enhancement
está descartado introducir en el futuro un framework,
Aunque no son filosofías y tecnologías nuevas, es en este
La razón de usar bytecode enhancement es una absoluta
momento cuando están teniendo un gran auge, en
necesidad, sin el mismo no sería posible conseguir el
concreto la AOP, pero hablar de AOP en Java casi no es
nivel de transparencia que ofrece JNIEasy, la alternativa
posible
sin
el
bytecode
enhancement,
frameworks más relevantes: AspectWerkz
los
seguramente AspectWerkz, más flexible que AspectJ.
dos
es usar las técnicas claramente intrusivas “y poco Java”
y AspectJ
que han acompañado hasta ahora las aproximaciones
están basados en esta técnica (existen otras como los
clásicas al problema.
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.
59
Actas del II congreso javaHispano
5
5.1
JNIEasy hacia una solución Java sin JNI
Sea la definición de una estructura:
// C: struct TestStruct { short a; int b;};
Estrategias de diseño
private static class TestStruct
La finalidad de JNIEasy es muy simple: sustituir a JNI, es
extends Structure {
decir, ser un nuevo Java Native Interface pero basado
public Int16 a = new Int16();
totalmente en Java desde el punto de vista del
public Int32 b = new Int32();
programador. De esta manera conseguimos eliminar la
public TestStruct() {
init(new Parameter[] {_int16,_int32});}
problemática mezcla de C/C++ y Java.
}
Hay dos aproximaciones o estrategias al problema:
1)
2)
Aparte de lo intrusivo que supone la necesidad de
Crear un modelo Java que represente los tipos de
derivar de la clase Structure, tampoco nos ofrece una
datos, las instancias y la forma de manipular la
natural simetría ni con una clase Java con dos atributos
memoria de un programa en C
short e int ni con la propia estructura C original.
Vincular la forma “normal” de manipulación y tipos
Veamos la definición de una callback: una callback en C
de datos de Java a la manipulación nativa
es una función diseñada para ser llamada normalmente
desde dentro de otra función en donde la dirección de
JNIEasy utiliza la segunda estrategia y el resultado es una
memoria de la callback ha sido dada como argumento:
mayor transparencia y familiaridad.
/* C callback: int callback(int); */
Analicemos la primera opción con varios ejemplos
private static class IncIntCallback
tomados de otro producto con similar objetivo [5]:
extends
Callback {
Int value = new Int(); // int
private Int _arg = new Int();
Pointer pValue=new Pointer(value); // int*
private Int _result = new Int();
public IncIntCallback() {
init(new Parameter[] {_arg},_result);}
En este ejemplo se hace una correspondencia directa
public void callback() {
entre el tipo de datos nativo C int con un objeto Java,
_result.setValue(_arg.getValue()+1);}
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
Como se puede comprobar los parámetros “formales” de
albergará la dirección de memoria que apunta al dato
la función están expresados como atributos de la
entero value. Como vemos se identifica un objeto Java
callback, expresada como una clase Java. Dichos
por cada dato nativo correspondiente que se quiere
atributos recibirán los valores de la llamada cuando se
poner en memoria.
produzca y el resultado se pondrá en un atributo
específico.
Veamos una llamada a función:
La consecuencia de éste enfoque es código Java que no
// int sprintf(const char*,…); C
parece Java” ni siquiera programación C.
Function sprintf = new Library("msvcrt")
.getFunction("sprintf");
El desarrollo de JNIEasy tuvo en cuenta este problema
AnsiString result = new AnsiString();
desde el principio, de ahí que uno de los principales
sprintf.invoke(null,result,
principios rectores fuera no tanto expresar en Java el
new AnsiString("Hello, %s!"),
modelo nativo C sino más bien lo contrario corresponder
new AnsiString("World"));
el modelo de trabajo normal de Java con el modelo
nativo. Para ello JNIEasy emplea un arsenal de técnicas
System.out.println(result.getValue());
desde la AOP via bytecode enhancement, código C y
//Output: Hello, World!
C++ con JNI, ensamblador e incluso generación
dinámica de código máquina.
Como se puede observar las cadenas que se pasan como
parámetros
se
envuelven
en
objetos
especiales
Punto de vista de JNIEasy:
AnsiString y el retorno también cadena es pasado
String cadena = new String("Texto");
como parámetro.
60
Actas del II congreso javaHispano
mismo puede decirse para los demás tipos básicos long,
Representa en JNIEasy desde el punto de vista nativo a
byte, char etc), por eso es también válido llamar como:
una cadena de caracteres (char) acabada en un nulo
Integer hwndObj = (Integer)method.call(new
('\0') instanciada en memoria a la que apunta un
puntero (de tipo const char*)
Object[] {null,"DDE Server Window"} );
que equivale a la
referencia String cadena en Java. Aunque el objetivo
En donde el método “call” es agnóstico en el tipo de
no se consigue 100% el alcance conseguido es
probablemente
el
más
alto
de
las
retorno (debe ser Object).
herramientas
disponibles.
Sólo es necesario obtener una sola vez el objeto que
representa el método, a cambio en todas las llamadas los
Lo demostraremos a continuación con ejemplos que nos
parámetros son supervisados comprobando que sean del
servirán para descubrir la “naturalidad” de uso y las
tipo adecuado, lo cual da una robustez mayor que la que
capacidades de JNIEasy.
5.2
ofrece la misma llamada en lenguaje nativo.
Es recomendable y más cómodo poner todas las
Llamadas a funciones
funciones de una DLL en una clase al efecto:
Consideremos la siguiente función de la API Win32:
public class User32 {
HWND FindWindow(
public static DynamicLibrary dll
LPCTSTR lpClassName, // class name
= JNIEasy.getInstance().
LPCTSTR lpWindowName ); // window name
getDLLManager().get("User32.dll");
public static GenericMethod[] methodList
Su finalidad es devolver el handler de la ventana cuya
= new GenericMethod[…];
clase y nombre (título) vienen dados por dos cadenas, la
static {
clase es opcional y puede ser NULL.
methodList[0] =
dll.addCMethod("FindWindowA",... );
JNIEasy necesita conocer cómo es dicha función para
... }
poder convertir la llamada Java en llamada nativa:
public static int findWindow(String
JNIEasy.getInstance().load();
className,String windowName) {
DynamicLibrary user32DLL =
CMethod method = (CMethod)methodList[0];
JNIEasy.getInstance().getDLLManager().get(
return method.callInt(new Object[]
"User32.dll");
{ className, windowName} );
CMethod method =
} . . .
user32DLL.addCMethod("FindWindowA",
Conscientes de que esta es una tarea tediosa, JNIEasy
int.class, // tipo de retorno
dispone de un generador de código Java a partir de una
new Class[] {
sucinta descripción de los métodos en XML. Ejemplo de
String.class,
// nombre clase
fragmento de declaración en XML:
String.class }, // nombre ventana
<method returnType="int" name="findWindow"
CallConv.STD_CALL );
// method representa al método C en la DLL
nativeName="FindWindowA" type="C"
int hwnd = method.callInt(new Object[]
conv="STD_CALL" >
<param type="String" name="className" />
{null, "DDE Server Window"} );
<param type="String" name="windowName" />
</method>
Notar que utilizamos directamente un objeto String
como argumento al igual que el null análogo al NULL
5.3
en C (y no un Pointer() cuyo contenido sea un nulo
Polimorfismo en funciones
según la anterior estrategia). El dato devuelto es un int
Cualquier programador en C conoce que aunque no es
lo que nos simplifica la programación y evita la
válido el polimorfismo de funciones en C, el lenguaje es
necesidad de objetos especiales, de hecho cuando es
lo suficientemente débil en su tipado para permitir un
necesario manejar int como objeto (como argumento
cierto grado de polimorfismo.
por ejemplo) JNIEasy usa el tipo básico Integer (lo
61
Actas del II congreso javaHispano
Por ejemplo, en el caso de un puntero a cadena de
retorno) es ANSI o Unicode cambiando el tipo de datos
caracteres,
del parámetro (o retorno). Para ello se dispone de las
const
char*,
aunque
nuestra
correspondencia “natural” en Java es un objeto String
interfases StringAnsi y StringUnicode:
o StringBuffer, la cabecera de la función C admite
CMethod method = jniEasyDLL.addCMethod(
realmente como parámetro un entero, la dirección de
"FindWindowW",int.class,
memoria de la cadena.
new Class[] {
JNIEasy evita la simplificación de identificar nombre de
StringUnicode.class,
función nativa – función Java , usando la más compleja
StringUnicode.class }, // window name
idea de “signatura” de función tal y como se emplea en
// class name
CallConv.STD_CALL);
C++ o Java para el polimorfismo de funciones: dos
int hwnd = method.callInt(new Object[]
funciones son diferentes si cambia el nombre o el tipo de
{null, "DDE Server Window"} );
alguno de los parámetros.
Aunque este método “espera” objetos StringUnicode
Por tanto sería válido añadir un nuevo método:
como parámetros, JNIEasy sabe que los objetos String
son compatibles, el resultado será una llamada a la
CMethod method = user32DLL.addCMethod(
"FindWindowA",int.class,
versión Unicode de FindWindow usando cadenas en
new Class[] {
Unicode.
int.class,
// nombre clase
int.class }, // nombre ventana
5.5
CallConv.STD_CALL );
Callbacks
Es posible programar callbacks en Java, funciones en
Java que serán llamadas directamente desde código
Pudiendo usar enteros (direcciones de memoria) para
indicar las cadenas.
nativo como si fueran funciones nativas.
Igualmente es posible obtener referencias a los métodos
Veamos un ejemplo: Win32 dispone de una función
EnumWindows que enumera a través de una callback
registrados con el mismo nombre:
todas las ventanas presentes en el desktop.
List methods =
BOOL EnumWindows(
user32DLL.findMethods("FindWindowA");
WNDENUMPROC lpEnumFunc, /* callback */
LPARAM lParam); /* app-defined value */
u obtener el método exacto indicando la signatura a
través de un objeto Signature :
El tipo WNDENUMPROC se define a su vez como un tipo
CMethodSignature sig =
puntero a función cuyo prototipo es el siguiente:
SignatureUtil.newCMethodSignature(int.class
BOOL CALLBACK EnumWindowsProc(
,new Class[]{String.class,String.class});
HWND hwnd, // handle to parent window
method = user32DLL.findCMethod(
LPARAM lParam );
"FindWindowA", sig);
5.4
Unicode
Una callback se define con JNIEasy como una clase que
deriva de CCallbackImpl (en el caso de C), que
El uso del Unicode está cada vez más generalizado y
implementa el método: Object
soportado por las herramientas software: los lenguajes
modernos como Java lo soportan nativamente, C y C++
la callback sea invocada desde código nativo.
API Win32 tiene todas las funciones que usan cadenas
public class EnumWindowsProc
con dos prototipos: ANSI (terminadas en A) y Unicode
extends
(terminadas en W).
CCallbackImpl {
private static final CMethodSignature
SIGNATURE =
JNIEasy es por defecto ANSI pero puede usarse Unicode
codificación
onCall(Object[]
params), dicho método es el que será llamado cuando
incorporan caracteres Unicode (wchar_t de 16 bits) y la
como
// app-defined value
por
defecto
o
SignatureUtil.newCMethodSignature(
explícita.
int.class,new Class[]
Voluntariamente podemos indicar que un parámetro (o
62
Actas del II congreso javaHispano
{int.class,int.class},
"enumWindows",
CallConv.STD_CALL );
new Class[]{int.class,int.class} );
public EnumWindowsProc() {
CCallback callback =
super(SIGNATURE); }
CallbackUtil.newCCallback(reflMethod);
public Object onCall(Object[] params) {
method.callInt(new Object[]{callback,
int hwnd =
new Integer(10)});
((Integer)params[0]).intValue();
5.6
int lParam =
Estructuras
((Integer)params[1]).intValue();
La definición de estructuras es donde JNIEasy se
System.out.println("handle:" + hwnd +
distancia claramente de las soluciones existentes, y en
" param:" + lParam);
donde entra a fondo la AOP y el bytecode enhancement.
return new Integer(1); }
Con ambas técnicas conseguimos “extender” una clase
}
normal Java para que represente a una estructura nativa,
Invocaríamos EnumWindows por ejemplo:
introduciendo de forma ortogonal, el “aspecto” de la
gestión de los atributos para que representen a la
method = user32DLL.addCMethod(
"EnumWindows",int.class,
imagen de una estructura C.
new Class[] {
Ejemplo, sea la estructura Win32 C:
EnumWindowsProc.class,
typedef struct tagPAINTSTRUCT {
int.class }, CallConv.STD_CALL );
HDC
method.callInt(new Object[]{
hdc;
// HDC = int en Win32
BOOL fErase; // BOOL = int en Win32
new EnumWindowsProc(),new Integer(10)});
RECT rcPaint;
BOOL fRestore;
Salida por pantalla:
BOOL fIncUpdate;
handle:65784 param:10
BYTE rgbReserved[32];
handle:328538 param:10 ...
} PAINTSTRUCT, *PPAINTSTRUCT;
Mientras el objeto callback esté en memoria es como si
En Java:
la función “se creara” desde el punto de vista nativo,
cuando se pierde vía garbage collector
public class PaintStruct {
pasa a ser
inaccesible (como si se destruyera código máquina)
int hdc;
liberando automáticamente sus recursos. El número de
int fErase;
callbacks en memoria es ilimitado. Detrás de las callbacks
Rect rcPaint = new Rect(); // Es embebido
de JNIEasy está una compleja mezcla de JNI, Java y
int fRestore;
código máquina generado dinámicamente desde Java.
int fIncUpdate;
byte[] rgbReserved =
Existe la posibilidad de que la definición de la función
new byte[32]; // Es embebido
que define una callback sea autónoma de JNIEasy, para
}
ello se usa Java Reflection, en donde un objeto callback
Rect sería una simple clase Java con cuatro enteros
interno de JNIEasy “representa” la función “normal” de
como atributos. En un archivo XML se indicaría además
Java. Sea por ejemplo:
que
el
atributo
embebidos
public class EnumWindowsProc2 {
(no
rcPaint
RECT*
o
y
rgbReserved
BYTE*).
Finalmente
son
la
sentencia:
public static int enumWindows(
int hwnd, int lParam) {
PaintStruct ps = new PaintStruct();
System.out.println("handle:" + hwnd +
" param:" + lParam);
return 1;
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
java.lang.reflect.Method reflMethod =
modifica desde Java hdc, por ejemplo, se modifica
EnumWindowsProc2.class.getDeclaredMethod(
63
Actas del II congreso javaHispano
también en la memoria nativa, un programa C/C++
// signatura de la callback Java
puede modificar ¡en cualquier momento! (no sólo
__int64 (__stdcall *suma)(int,int);
dentro de una llamada iniciada desde Java) el atributo
suma = (__int64 (__stdcall *)(int,int))
hdc , percibiendo ese cambio en Java cuando se acceda
findCBAddress(sig);
al mismo. La interacción transparente memoria Java-
__int64 res = suma(1,2);
memoria nativa es una de las características más
avanzadas de JNIEasy.
llama desde código nativo al método Java exportado
como si fuera un método C “normal”.
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
5.8
aplicaciones basadas en JNIEasy evitando los consabidos
JNIEasy también aporta herramientas para acceder a
memory leaks de los que han estado plagadas las
C++
métodos C++ en DLLs, clases Java emulando clases
aplicaciones C/C++.
C++ cuyos métodos y atributos “normales” pueden ser
visto como métodos y atributos “C++” etc.
Conseguimos en resumen una programación “nativa”
con Java, con filosofía Java y con mayor robustez y
6
seguridad que usando un lenguaje nativo.
5.7
¿Hacia un desktop “muy” Java?
El tiempo lo dirá, JNIEasy es un paso más en esa
Exportación de funciones
dirección.
Una de las características más interesantes es la
Referencias
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
[1]
JNIEasy. http://www.jnieasy.com
exportación de un método de una DLL pero ¡desde Java!.
[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/javamedia/jmf/
[5]
JNIWrapper. http://www.jniwrapper.com
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)";
64
Actas del II congreso javaHispano
Guasaj. Un framework de programación basado en componentes
Benito Mateo, Urko
Blesa Jarque, Ángel
Lop lis, José Javier
Golf Enparantza, Nº 1, 3 A
Plaza del Olmo, Nº 5, 2º Piso
C.P. 20.160 Lasarte (Gipuzkoa)
itily@ya.com
C.P.44770 Escucha (Teruel)
euplaablesa@arco-elect.es
Isabel la Católica, Nº 16-18, Piso
5 C,Esc. Izq.
Abstract
C.P. 50009 Zaragoza
josejavierlop@terra.es
1 Motivación. Origen de guasaj.
En el ciclo de vida de un proyecto, independientemente del
proceso de desarrollo que se utilice (RUP, FDD, XP, etc…) en
El origen desde el cual guasaj fue concebido fue crear un
un determinado momento se debe pasar del análisis de los
entorno de trabajo en el cual se defina un procedimiento
requisitos al diseño e implementación del mismo.
para plasmar el análisis y diseño de la solución de un
problema en un conjunto de componentes reutilizables.
Los patrones de diseño hacen colaborar un conjunto de
clases e instancias de las mismas, para solucionar un
Con ello se pretende aumentar la productividad a través de
problema determinado permitiendo obtener una solución con
dos cuestiones:
buenas
•
características
de
acoplamiento,
cohesión,
granularidad, rendimiento, adaptabilidad, evolución, etc. , pero
implementación de las funciones descubiertas en el
con los patrones de diseño sólo no basta, no dicen
análisis y el diseño.
directamente que modelo superior crear para hacer colaborar
N
paquetes
de
casos
de
uso,
y
que
El establecimiento de un procedimiento claro de
•
permanezcan
La reutilización automática del trabajo realizado en el
paso anterior.
desacoplados, independientes, reutilizables, etc..
En la búsqueda de este modelo superior surge el componente
En primer lugar se pretende crear un esquema de clases
de
sencillo para la implementación de componentes, con un
software
como
unidad
independiente,
cooperativa,
ciclo de vida, en la llamada a sus servicios, lógico y que
desacoplable, etc.
cumpla
Lo que pretendemos con este proyecto es proponer una
metodología
de
organización
de
código
en
torno
a
bien
conocidos(MVC,
Observer,
resultados
reutilizables
de
diseño
entre el modelo conceptual de una aplicación y su
correspondiente implementación.
a la implementación de la solución en código de una manera
con
patrones
flexible, creando una asociación rápida y semiautomática
(historias, requisitos funcionales, casos de aplicación, etc…)
y
los
una implementación de la misma, sencilla, pero potente y
Locator, …) que nos lleve del análisis de los casos de uso
repetible
de
creación de aplicaciones basadas en componentes pasar a
ViewDispatcher,
Factory, Command, Facade, VO, Service Activator , Service
metódica,
premisas
locator, factory, etc…). A través del estudio de la filosofía de
componentes con una estructura basada en patrones de
diseño
las
sobradamente conocidos [1] (MVC, command, service
Con este proceso se pretende eliminar, dentro de lo posible,
en
el problema de tener que “reinventar la rueda” en cada
diferentes proyectos..
proceso de análisis y diseño de un determinado problema,
Keywords: framework, patrón, componente, metodología.
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.
65
Actas del II congreso javaHispano
En definitiva, ir un paso más allá de los patrones de diseño
modelo, una gestión clara de los datos del proceso, un
en el establecimiento de un lenguaje común para la
manejo de excepciones efectivo, y una posibilidad
nomenclatura
reutilización practica y rápida, desde el principio, de la
de
las
funciones,
comportamiento
y
codificación,
arquitectura de un sistema.
En la labor de desarrollo de proyectos software se
una
serie
de
problemas
con
Dificultad
en el
paso de análisis, al
diseño
y
funcionalidades del sistema en paquetes y su posterior
a
codificación
no
está
suficientemente
sistematizado.
•
•
Estudio de los requisitos.
•
Análisis
de
patrones de diseño. Se hace complicado pasar de
pequeñas implementaciones de soluciones en una serie
la
de
solución.
las
Modelo
entidades
del
conceptual.
problema.
Agrupación en paquetes conceptuales.
•
Diseño de la solución. Patrones. Establecimiento de la
arquitectura. Diseño de pruebas. Cumplimiento de
la problemática concreta de un gran proyecto, a las
requisitos no funcionales, etc…
•
Codificación. Llegado este momento en determinadas
metodologías podemos estar en un estado más o menos
de clases y objetos aplicando unos determinados
avanzado en la identificación de clases y métodos a
patrones, a la implementación de una serie de paquetes
implementar, pero en general se dista bastante de tener
o componentes que desarrollen una parte concreta,
una visión clara y lo más importante, acertada y con
independiente, reutilizable, extensible y configurable de
posibilidades de ser la definitiva. Esto deriva en una
la aplicación de un tamaño considerablemente mayor.
lógica de negocio más o menos dispersa en métodos de
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 …
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
Dificultad de programación para el interface en lugar de
no nos provoque más de un dolor de cabeza y desde
la implementación.
luego una merma en nuestra productividad.
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.
•
de
consecución de la solución a un proyecto:
soluciones a un nivel más micro que aportan los
•
exportación
proceso similar al que se describe a continuación para la
Descubrimiento
cotidianos, debido en parte a la dificultad para abstraer
•
la
3 Del análisis a la programación. Pasos y
trabas intermedias
Poca o ninguna aplicación de patrones de diseño para
resolución de problemas genéricos en los proyectos
•
que
de software, salvando sus peculiaridades, se sigue un
codificación. La identificación y agrupación de las
paso
manera
En cualquiera de las metodologías o procesos de desarrollo
demasiada
frecuencia, como son:
•
tal
funcionalidades desde un proyecto a otro sea automática.
2 Problemas detectados en el desarrollo de
programas en la actualidad
presentan
de
de
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
No se define una separación clara entre al estructura de
probada circunstancias que se dan en la programación
datos que almacenan el estado del sistema en cada
cotidiana.
momento de ejecución del mismo, y las diferentes
operaciones que se pueden realizar sobre dichos datos.
El uso de patrones hace que las porciones de código
resultantes sean robustas, flexibles, extensibles, adaptables,
No existe, en general, un procedimiento sistemático para
optimizadas y fiables, de tal manera que el conjunto de la
codificar la funcionalidad que se requieren (casos de uso,
aplicación también herede dichas cualidades. Esto es lo que
historias,
se pretende pero en el camino para lograrlo se tiene una
requisitos
arquitectónicos,
características
funcionales y no funcionales, etc), de tal manera que
mantengamos desde el principio un separación entre vista y
66
Actas del II congreso javaHispano
serie de imponderables, que hacen que las decisiones de
•
El cliente de un componente estará desacoplado del
mismo, ni siquiera a través de una interface. La
diseño no sean triviales.
resolución del componente y del método a ejecutar se
En el momento de diseñar la solución para una aplicación el
realizará en tiempo de ejecución
arquitecto/diseñador debe tener una concepción de las
entidades y la colaboración entre las mismas que le harán
•
Los componentes que participan en una aplicación, la
desempeñar la solución requerida, así como una capacidad
descripción de los mismos en cuanto a comportamiento
de abstracción para descubrir entre estas entidades la
y aspectos (acceso, relaciones, vista, excepciones, log)
problemática que encierran y que parte de ésta, está
debe tener un soporte de configuración exterior al
contemplada como patrón sobradamente conocido.
código (archivo xml de configuración).
•
3.2 Problemática de los patrones en la
codificació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
El uso de patrones de diseño en la solución de una
de un componente sea llamado desde otro puede
aplicación facilita el paso del diseño a la implementación por
provocar en determinadas circunstancias que
estar estos ya codificados en multitud de ocasiones. Aún
respuesta de éste sea de un tipo o de otra
así, hay un nivel de abstracción intermedio en las soluciones
genéricas que aportan los patrones, y los problemas de
la
•
Un
componente
tiene
una
lógica
de
negocio
modelado, diseño, empaquetado, y reutilización de código
representado por un BO (Bussiness Object) con los
que
se necesitan en los proyectos con una tamaño
métodos operativos, y además un componente trabaja
considerable, sobre todo en sistemas en los que se
con un conjunto de datos en forma de VO (Value
desarrollan una serie de aplicaciones (suite) para dar una
Object).
serie de servicios integrales a una empresa.
•
El estado en memoria de un componente en un
elaboración de un
determinado momento de ejecución (por ejemplo, un
framework que encapsule las buenas prácticas de los
servidor de Chat, con una serie habitaciones y unos
patrones
La solución puede pasar por la
los
usuarios en las mismas, en un determinado momento)
programadores sean capaces de representar el modelo
se debe reflejar en este BO. Pero no una instancia del
lógico de la solución del problema, expuesto en el análisis,
BO por cada elemento a reflejar. Por ejemplo, el
con un buen diseño, una buena arquitectura y un código
componente “Habitación” en una aplicación de chat,
ampliamente
estaría formado por un BO con las operaciones y una
sobradamente
reutilizable
conocidos
sin
tener
y
haga
que
que
implementar
lista de posibles habitaciones.
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
•
de los datos que puede manejar. Los componentes son
framework garantiza la herencia de la mayoría de los
elementos de peso de tal manera que en el sistema no
patrones de diseño más utilizados, sin prohibir en absoluto
tendremos múltiples instancias de un componente[1],
la implementación de alguno de los mismos para cubrir una
sino que será el componente el que maneje los datos
determinada necesidad.
4
De esta manera un componente será gestor y almacén
necesarios y trabaje con las operaciones para construir
y manejar el estado del sistema en un momento dado.
Condiciones deseadas en la solución
Un framework que pretendiese implementar una solución
•
Cuando en una vista de un componente se lleve a cabo
para la problemática anteriormente descrita deberá poseer
un cambio, dicho cambio deberá ser reflejado de alguna
una serie de características como:
manera en el estado de la lógica del componente, en su
•
Guiarse por un patrón de comportamiento como el MVC
para la separación de vista, modelo y controlador.
•
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
El código resultante debe quedar en forma de
herramientas seleccionamos un elemento y desde otro
componente reutilizables, y cumplir con el paradigma y
componente,
filosofía de construcción de aplicaciones basadas en
seleccionado. No podemos desde una vista de un
componentes tal y como se detalla más en profundidad
componente acceder directamente a la vista de otro,
en [2].
67
queremos
acceder
al
elemento
Actas del II congreso javaHispano
debemos pasar por el modelo y solicitar algún atributo
incluso plataforma, si están diseñados para ello. Por
que nos de la información que requerimos.
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
5 Características de los componentes
guasaj
estilo y fuentes de una aplicación, un componente
calendario, un componente calculadora, etc…
Un componente guasaj es un conjunto de clases diseñadas
De esta manera en la elaboración de una solución
para llevar a cabo una serie de funciones relacionadas con
completa
un problema del modelo de negocio del sistema o
problema,
partiremos
del
modelo
siguiente manera:
arquitectura, estando este acompañado de un fichero de
•
descripción de las características y posibilidades de
Se plantea una serie de requisitos o funcionalidades a
desarrollar.
ejecución de dicho componente. Ejemplo, roles de usuario,
pre y post ejecuciones, controlador de excepciones,
•
métodos virtuales…
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.
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
tanto
a
J2EE
como
J2ME.
Se realiza una agrupación en paquetes guiándose por
una
plataforma objetivo de guasaj es la J2SE aunque su filosofía
extrapolable
un
tradicional de resolución de problemas software, de la
desarrollar una función de carácter más amplio dentro de la
es
para
determinada
premisa
pudiendo
esta
ser,
agrupación por función, agrupación por complejidad,
Todo
agrupación
componente aporta un mecanismo de llamada a sus
por
arquitectura,
agrupación
por
departamento lógico del cliente, etc, etc.. Suele ser en
servicios, un método de gestión y acceso a sus datos, así
este momento donde empiezan a surgir los problemas
como un control de sus vistas, manejo de excepciones y
separación de responsabilidades entre las entidades del
control de acceso.
sistema. Aquí evidentemente no hay magia que valga,
Dentro de los tipos de componentes que podemos
la
desarrollar se pueden encontrar 2 tipos principales con sus
responsabilidades de cara a un diseño u otro es propia
decisión
final
peculiaridades y variantes:
del
arquitecto
de
agrupación,
/diseñador,
siendo
separación
muchas
de
veces
equivalentes soluciones con topologías de entidades
diferentes.
Componente entidad: Son componentes que intentan
Una cuestión que puede y debería ayudar sobremanera en
representar el modelo lógico de negocio propio de un
este paso del proceso de desarrollo, sería el hecho de saber
proyecto asumiendo una serie de características de la
exactamente
solución final. Estos componentes desarrollan una función,
el
procedimiento
de
codificación
que
seguiremos para llegar a implementar esta entidad, e
tienen una responsabilidad y unos mecanismos o reglas de
igualmente los servicios a los que tendremos acceso sólo
interacción con otros componentes de entidad o de servicio.
por el hecho de implementar la entidad de acorde a este
Un ejemplo de componente representativo de una entidad
procedimiento / framework de programación.
del modelo de negocio podría ser los componentes cliente,
factura, proveedor, empresa, albarán, etc... por ejemplo, en
La idea radica en crear una equivalencia entre cada uno de
una aplicación de gestión. En un sistema de tratamiento de
los términos utilizados en el análisis funcional de la
señales provenientes de un sistema de instrumentación
aplicación y la codificación de los mismos. Saber medir que
electrónica, estos pudieran ser, equipo, señal, punto de
implicaciones tendrá el hecho de utilizar palabras como
medida, etc. En general los candidatos a este tipo de
paquete, clase, entidad, atributo, relación, caso de uso,
componentes pueden ser los provenientes del análisis
servicio, etc.… en la codificación del sistema.
conceptual del dominio del problema.
6
Componentes genéricos de servicio: Componentes que
permanecen
peculiaridades
completamente
de
un
independientes
determinado
proyecto
de
las
siendo
totalmente reutilizables en otro ámbito de ejecución e
68
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
•
Independencia de componentes.
•
Primero, indicar si queremos manejar vista o no.
•
Variación del comportamiento de un componente según
•
Segundo, indicar que método de que componente
queremos que maneje la respuesta en forma de vista.
una definición exterior, sin modificar el código.
•
Estandarizar la nomenclatura y tipo de clases al crear
•
Tercero y último, si para ese componente queremos
instanciar una nueva vista o manejar una que pasamos
un componente reutilizable.
•
en la llamada al método. Tres en uno.
Crear un elemento amigable tanto para el analista como
para el programador del sistema, pasando por el
Así,
teniendo
la
ventaja
de
una
separación
entre
arquitecto y el diseñador.
componentes, podemos acceder a través de las funciones
del contenedor (éste las resuelve en tiempo de ejecución,
6.1 Localización de componentes por
nombre.
no de desarrollo), a otros componentes para pasarles
(notificarles)
resultados
de
operaciones
de
otros
Para tener acceso a los servicios de un componente
componentes. Esto corresponde con la teoría de inversión
debemos
dicho
de control [3], por la cual es el contenedor el que llama a
componente. Para ello, pasaremos un nombre único con el
nuestras clases para realizar ciertas funcionalidades en un
que denominaremos unívocamente a un componente dentro
momento dado.
primero
localizar
una
instancia
de
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.
llamado. Esta utilidad resulta interesante cuando queremos
plano de una
operación y recibir la respuesta de esta
cuando finalice la misma, sin que tengamos por ello
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
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
según los parámetros pasados.
que no podamos seguir la ejecución de algo concreto sin
este componente o servicio pero eso no impide que
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,
Sin tener que esperar a que termine la ejecución del método
tener un mecanismo automático de ejecución en segundo
6.2 Ejecución de métodos de los
componentes dinámicamente.
6.3
6.4 Posibilidad de llamar a métodos no
bloqueantes.
podamos ejecutar otras opciones del programa y ser
avisados cuando se haya
cuando haya vencido el plazo de timeout.
6.5 Concentración del manejo de
excepciones.
A
través
de
un
HandlerException
tenemos tres
69
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).
funciones relacionadas con la vista:
localizado el componente o
Actas del II congreso javaHispano
6.6 Control de acceso a los métodos y
componentes por rol de usuario.
original con éstos. Un ejemplo de preejecución, puede ser
A través del fichero de descripción del componente se
incluir un sistema de logs a un determinado método. En el
puede indicar que roles de usuario tendrán acceso a cada
caso de la postejecución, un posible ejemplo sería la
método. Lo único que se debe realizar es activar en el
elaboración de un informe al término de la ejecución de un
contenedor guasaj el rol de usuario activo. En tiempo de
método, necesitando para ello, los parámetros de entrada,
ejecución comparará si el rol activo coincide con alguno de
respuesta del método original y los posibles cambios que
original, puede modificar los mismos, y llamará al método
los que tiene permiso de ejecución. El proceso común será
haya podido originar dicha llamada, como escritura en base
aprovechar el momento en el que pidamos validación al
de datos, cambios de estado, alteración de ficheros o
usuario para recoger de este el rol de usuario y activarlo en
configuraciones, etc…
guasaj.
Y por último, un ejemplo de intercepción sería el hecho de
Para este usuario cuando ejecute el resto de
operaciones su nivel de acceso vendrá determinado por
dicho rol.
6.7
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
Métodos virtuales.
el componente destino que se ejecutaría ya con los datos
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,
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 los
componentes guasaj
atiende a los clientes conectados, y recibe peticiones de los Los componentes guasaj están concebidos desde un
mismos. Este componente es reutilizable en multitud de principio con una vocación de reutilización de los mismos en
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
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,
llame a dicho método virtual.
separación de responsabilidades, posibilidades de relación
6.8 Preejecución, postejecución e
intercepción de métodos.
desde cualquier parte de la aplicación.
entre componentes y acceso a los servicios de los mismos
En la descripción de un método, dentro del archivo de
configuración del componente, podemos especificarle un
8
Conclusiones
En la ejecución de un proyecto software, el paso del análisis
método que se ejecutará antes que este. Este último recibirá
del problema al diseño y codificación presenta una serie de
los parámetros del método original para su ejecución. En el
dificultades para asignar las diferentes responsabilidades
caso de queramos una postejecución, podemos definir un
entre las unidades de código que vamos creando. Dentro de
método que se ejecutará con posterioridad a la ejecución
las unidades de código queremos mantener una separación
del método original. En este caso este método recibirá tanto
entre la lógica de negocio y la vista. Gran parte del código
los parámetros del método original como la respuesta
que generamos para la solución de un determinado
producida por este. Y por último, en el caso de la
problema deberíamos poder reutilizarlo en parte o por
intercepción, el método interceptor recibe los parámetros del
completo, con alguna pequeña variación de configuración
70
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 John
Vlissides. Design Patterns. Element of Reusable ObjectOriented Software, Addison-Wesley, 1995.
[2]
Claudia Patricia García Zamora y Samuel Garrido.
Programación basada en componentes. CINVESTAV México
D.F 4 - Noviembre -2003.
[3]
Mike
Spille,
Inversion
of
control
http://www.pyrasun.com/mike/mt/archives/2004/11/06/15.46.14
/index.html
71
Actas del II congreso javaHispano
72
Actas del II congreso javaHispano
Extensión del patrón Observador para la integración de eventos de
componentes heterogéneos.
Luis Rodero Merino
Miguel A. Ortuño Pérez
Luis López Fernández
Univ Rey Juan Carlos, DIET
lrodero@gsyc.escet.urjc.es
Univ Rey Juan Carlos, DIET
mortuno@gsyc.escet.urjc.es
Univ Rey Juan Carlos, DIET
llopez@gsyc.escet.urjc.es
2 El patrón Observador
Abstract
En este artículo presentamos una extensión al ya conocido
El patrón Observador es uno de los 23 patrones
patrón Observador. Esta extensión está orientada a
descritos en [2]. Este patrón “Defines a relationship
facilitar la monitorización de eventos provenientes de
between a group of objects such that whenever one
distintos componentes de un sistema. Este artículo también
object is updated all others are notified automatically”.
contiene un ejemplo de como aplicar este patrón dentro
El objeto observado no necesita saber nada acerca de los
del contenedor PicoContainer.
observadores. Son los observadores quienes deben
registrarse como 'oyentes' para poder recibir eventos.
Palabras clave: Observador, observable, patrón,
contenedor, componente.
Esto
permite
el
desarrollo
de
aplicaciones
con
componentes poco acoplados. el bajo acoplamiento se
considera una ventaja ya que simplifica la posterior
1. Introducción
reutilización de componentes.
El patrón Observador es uno de los más ampliamente
Los oyentes reciben notificación de todos los eventos
utilizados en la programación de sistemas, aunque a
generados en los objetos observados. Pueden registrarse
veces incluso el programador no sabe que lo está
en cualquier momento durante el ciclo de vida del
usando. Hay dos roles básicos en este patrón: el
componente.
componente
observable,
que
lanza
eventos
para
Este patrón debe aplicarse cuando:
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
muestra
una
extensión
del
es un observador que recibe eventos de la interfaz, y la
vista recibe eventos referidos a cambios en el modelo.
Observador, y describe sus limitaciones, mostrando las
dificultades que pueden surgir al usarlo. Después se
que
hemos
El bajo acoplamiento es un requerimiento básico del
diseño..
patrón Modelo Vista Controlador, donde el controlador
con una definición más completa y profunda del patrón
extensión
•
parte de otros patrones más complejos tales como el
patrón
de eventos dentro de un sistema. El artículo comienza
la
El número de oyentes puede variar durante el ciclo de
vida del objeto.
El patrón es bastante sencillo, y puede encontrarse como
Observador que simplifica el manejo de distintas fuentes
explica
•
en la Figura 1.
uno capaz de generar sus propios eventos.
artículo
Cambios en algunos de los objetos del sistema
requieren cambios en otros objetos del mismo grupo.
Este patrón implica dos roles distintos, como se muestra
desde
distintos componentes dentro del mismo sistema, cada
Este
•
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.
73
Actas del II congreso javaHispano
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 que
deben observar, aunque es posible que sólo sepan los
eventos que quieren recibir. Si el oyente es un
componente externo al sistema, entonces es posible que
no sepa cuales son esos componentes.
Figura 1 Patrón Observador
• En algunos casos, puede que no todos los observadores
deban ser informados acerca de todos los eventos que
ocurren en el sistema, incluso aunque estén interesados
en ellos, por razones de seguridad o rendimiento.
3 Desventajas del patrón Observador
• Si los observadores tardan un tiempo apreciable en
procesar eventos, el rendimiento del sistema puede verse
afectado. Este hecho se agrava si los componentes son
externos al sistema.
Debido a su sencillez, el patrón Observador tiene
algunas desventajas:
• Todos los oyentes reciben todos los eventos lanzados, sin
• Si se generan muchos eventos, el tiempo para crearlos y
• A menudo los sistemas tienen varios componentes que
reenviarlos puede ser no despreciable. Esta circunstancia
se agrava cuando se utiliza un estrategia push para la
transmisión de la información referida al evento. Esto
significa que el evento transporta toda esta información,
por ejemplo el nuevo estado del componente observado.
Para solucionar este problema debería ser posible fijar
los eventos que deben ser creados y los que deben ser
ignorados.
distinción. Esto es ineficiente, y los observadores
deberían ser capaces de registrarse sólo para aquellos
eventos en los que estén interesados.
son generadores de eventos, y varios componentes que
escuchan por esos eventos. Las relaciones entre todos
estos componentes pueden ser difíciles de maneja. Ver
por ejemplo la Figura 2
• La implementación de políticas referidas al manejo de
eventos no es una tarea trivial, ya que puede implicar el
trabajar con componentes y oyentes repartidos a través
de todo el sistema.
• Java no implementa herencia múltiple. Por lo tanto,
muchas clases no serán capaces de heredar de
java.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
Figura 2 Varios componentes observados y
observadores
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
Gamma et al. [2] ya sugerían utilizar un mediador
debe generar estos eventos.
(patrón Mediador [2]), llamado Gestor de Cambios. El
mediador mantiene las relaciones entre oyentes y
4 Administrador de Eventos, Anunciantes
componentes observados (Figura 3).
Los problemas descritos en la sección anterior fueron
detectados durante el desarrollo de un sistema peer to
74
Actas del II congreso javaHispano
peer. Un requisito importante es que debíamos ser
Administrador de Eventos). Si es así, la instancia del
capaces de monitorizar y registrar todo lo que ocurriera
evento
en
el
nodo
búsquedas...).
(eventos
Nos
referidos
enfrentamos
a
al
es
creada
y
enviada
al
Administrador de Eventos. Este notificará el evento a los
conexiones,
problema
correspondiente
observadores
de
monitorizar todos estos eventos, y concluimos que lo
Este mecanismo tiene las siguientes ventajas:
• Los componentes no necesitan heredar de la clase
java.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 un
punto.
En la Figura 4 vemos como los anunciantes se sitúan
entre el Administrador de Eventos y los componentes
4.3
Figura 3 Gestor de Cambios
Administración
centralizada
de
eventos
El uso de un Administrador de Eventos y un Anunciante
mejor era utilizar un sistema de gestión de eventos
permite usar una implementación centralizada de la
centralizado.
gestión
Más
adelante
añadimos
nuevas
de
eventos.
Los
programadores
pueden
capacidades al nodo, por ejemplo la posibilidad de fijar
centrarse en la lógica de los componentes, ya que la
filtros de eventos.
creación y reenvío de eventos son manejados por el
Anunciante correspondiente. Además, la administración
Para todo ello, hemos desarrollado una extensión del
de eventos es facilitada ya que las tareas relacionadas
patrón Observador, introduciendo Anunciantes y un
con los eventos se realizan en un único punto. Así, la
nuevo Administrador de Eventos que sustituye al Gestor
especificación de políticas referidas a notificaciones
de Cambios.
4.1
(filtros, permisos...) puede hacerse llamando a los
métodos adecuados del Administrador de Eventos. Sin
Administrador de Eventos
este, la implementación de políticas es una tarea
El Administrador de Eventos sigue la misma idea que el
complicada
Gestor de Cambios explicado en la sección 3. Se sitúa
componentes observables.
entre oyentes y componentes observables, y mantiene
implica
trabajar
con
todos
los
Un Administrador de Eventos, o un componente similar,
las relaciones entre estos. Pero también añade algunas
podría estar presente dentro de un contenedor de
capacidades nuevas:
componentes. Así, el manejo centralizado de eventos
• Un observador puede registrarse para recibir cualquier
sería
evento, sin especificar el componente que lo genera.
Esto es, la administración se centra en eventos y no en
componentes.
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.
• Pueden especificarse filtros de eventos. Si algún evento
no pasa esos filtros, no es reenviado a los observadores.
• El Administrador de Eventos contiene una cola de
eventos que puede ser activada al inicio. Los eventos son
almacenados en la cola, y un hilo dedicado se encarga de
reenviar los eventos de la cola a los oyentes.
4.2
que
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
75
Actas del II congreso javaHispano
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.
Figura 4 Administrador de Eventos, Anunciantes
5 Administrador de Eventos en el
contenedor 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
Figura 5 Diagrama de clases del Administrador de
Eventos y de los Anunciantes
difíciles.
Sin embargo, utilizar eventos para la comunicación entre
componentes
desarrollan
es
una
buena
componentes
opción
con
bajo
cuando
Sin embargo, no hemos podido encontrar ningún
se
contenedor que proporcione un servicio de manejo de
acoplamiento.
eventos como el descrito en la sección 4.3.
Además, nuestra experiencia demuestra que es mucho
Por ello, hemos tomado el contenedor PicoContainer [6]
mejor y más factible utilizar eventos cuando se necesita
monitorizar el sistema desde un componente externo.
e intentado añadirle capacidades para la gestión de
En los últimos años nuevos contenedores han aparecido
contenedor son básicamente dos:
dentro
del
complejidad
mundo
y
Java.
capacidades,
Aunque
diferentes
comparten
el
eventos. Las razones por las que hemos elegido este
en
• Es código de fuente abierta, que puede ser leído y
mismo
modificado.
objetivo básico de facilitar el desarrollo de sistemas
• Es un contenedor sencillo. Sólo resuelve dependencias
mediante componentes. Las tareas básicas que suelen
entre componentes, y no proporciona ningún servicio
extra. Esta simplicidad facilitó la comprensión y posterior
modificación de su código
realizar son:
• Instanciación y ensamblaje de componentes. El patrón
Inversión de Control es usado normalmente para esta
tarea. Las dependencias entre componentes son
automáticamente resueltas por el contenedor.
5.1
Cambios realizados en PicoContainer
Hay dos cambios básicos que hemos realizado sobre el
• Mantenimiento del ciclo de vida de los componentes.
contenedor.
• Proporcionar servicios tales como logging,
Primero ,un Administrador de Eventos ha sido añadido.
configuración...
Otras entidades puede acceder al mismo para fijar
• Servicios avanzados tales como pools de threads, fuentes
políticas de filtrado, para registrarse como observador,
de datos...
etc.
76
Actas del II congreso javaHispano
Segundo, a todos los componentes se les asigna un
Anunciante que envía eventos referidos al ciclo de vida
package jhii;
del componente. Esto es, notifica cuando el componente
public class PicoDefaultAdviser extends AdviserDefaultImpl
implements PicoComponentAdviser {
es iniciado, parado. Este Anunciante no es llamado por
el componente, sino por el mismo contenedor, que es el
public void componentStarted(){
que controla el ciclo de vida. Así el componente no
if(component != null)
necesita heredar de ninguna clase, ni implementar
advise(new ComponentStartedEvent(component));
ninguna interfaz o llamar a ciertos métodos. No es
else
necesario cambiar el componente en absoluto, todo es
advise(new ComponentStartedEvent(this));
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
public void componentStopped(){
if(component != null)
su propia implementación. Por supuesto, cualquier
componente puede tener varios Anunciantes.
Para
conseguir
esto,
DefaultPicoContainer
hemos
para
extendido
crear
la
advise(new ComponentStoppedEvent(component));
la
clase
nueva
clase
else
advise(new ComponentStoppedEvent(this));
PicoEventAbleContainer. Esta nueva clase mantiene las
}
relaciones
public void componentDisposed(){
entre componentes
y
Anunciantes.
Los
Anunciantes manejados por este contenedor deben
if(component != null)
implementar la interfaz PicoComponentAdviser, tal y
advise(new ComponentDisposedEvent(component));
como se define en la Figura 6.
else
package jhii;
advise(new ComponentDisposedEvent(this));
public interface PicoComponentAdviser extends Adviser {
}
public void componentStarted();
}
public void componentStopped();
Figura 7 PicoDefaultAdviser interface
public void componentDisposed();
}
Figura 6 PicoComponentAdviser interface
Cuando se instancia cualquier componente, si el
componente implementa la interfaz PicoAdviserOwner
Referencias
significa que posee su propio Anunciante capaz de
notificar eventos acerca de su ciclo de vida.. Así, el
[1]
Apache Avalon framework. http://avalon.apache.org
contenedor utilizará este anunciante para notificaciones.
[2]
E Gamma, R. Helm, R. Johnson, J. Vissides. Design Patterns
Addison-Wesley, 1995. ISBN: 0201633612
[3]
JavaTM 2 Platform, Standard Edition, v 1.4.2, API
Specification http://java.sun.com/j2se/1.4.2/docs/api/
[4]
Java/J2EE Spring framework
http://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/mvcindex.html.
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.
77
Actas del II congreso javaHispano
78
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
carlos@apache.org
proporcionada por Acegi es mucho mayor, y además
Abstract
permite la integración con JAAS, utilizándolo en la fase
Uno de los aspectos que toda aplicación debe considerar es
de autenticación.
la seguridad, entendiendo como tal la necesidad de saber
Acegi Security System [1] es un framework creado por
que el usuario es quien dice ser (autenticación), y permitirle
Ben Alex e íntimamente ligado al proyecto Spring [2], si
acceso sólo a aquellos recursos necesarios (autorización).
bien no requiere su utilización en nuestra aplicación, que
Acegi
facilita la tarea de adoptar medidas de seguridad en
Security
System
for
Spring
proporciona
la
funcionalidad necesaria para adoptar mecanismos de
aplicaciones
seguridad en aplicaciones Java utilizando características de
aplicaciones web. Y lo mejor de todo es que es open
programación orientada a aspectos, de forma transparente
source, sin coste de licencias y con la seguridad añadida
para el desarrollador, sin necesidad de desarrollar código,
que proporciona el respaldo de un enorme y creciente
utilizando para ello el soporte prestado por el framework
grupo de usuarios que lo están utilizando, y con un
Spring, pero siendo posible utilizarlo en aplicaciones no
manual de referencia con más de 50 páginas que no
desarrolladas con Spring. En este artículo se detallarán las
tiene nada que envidiar a la documentación de un
funcionalidades que ofrece y una visión detallada sobre la
producto comercial.
arquitectura del sistema, así como un simple ejemplo que
sean
aplicaciones
standalone
o
La arquitectura de Acegi está fuertemente basada en
demostrará la sencillez con la que se puede adoptar su uso.
Keywords: Acegi, Spring Framework,
autenticación, autorización, java.
Java,
interfaces y en patrones de diseño, proporcionando las
implementaciones
seguridad,
numerosos
más
puntos
de
comúnmente
extensión
utilizadas
donde
y
nuevas
funcionalidades pueden ser añadidas. Esta arquitectura
1
puede hacer un poco difícil seguir el flujo de ejecución al
Introducción
principio, pero una vez comprendida la idea global se
Aplicar una política de seguridad a una aplicación es un
acepta como el precio necesario para poder disfrutar de
aspecto que afecta a prácticamente la totalidad de las
un framework con una gran potencia.
aplicaciones empresariales, y si no se adopta desde una
Como ejemplo se mostrará la configuración realizada en
perspectiva correcta puede llegar a ser una carga que
el proyecto ONess [3] para la protección de peticiones
afectará y lastrará el desarrollo del sistema.
http en una aplicación web, además de mencionar uno
Si bien existe el estándar JAAS (Java Authorization and
de los completos ejemplos que se distribuyen con el
Authentication Service) que pretende cubrir tanto
proyecto.
autenticación como autorización, su adopción dista
mucho de ser sencilla y portable, debido a que el soporte
1
proporcionado por los contenedores de aplicaciones
Autenticación
Antes de poder tomar decisiones sobre si un usuario
dista mucho de ser adecuado, existen incompatibilidades
puede acceder o no a un recurso, el usuario debe
entre distintas implementaciones y cada contenedor
identificarse para comprobar su identidad. Para ello
requiere una configuración distinta, normalmente con
adición de librerías. Por otro lado la funcionalidad
79
Actas del II congreso javaHispano
existe el interfaz Authentication, desde el que se puede
El proveedor DaoAuthenticationProvider merece una
acceder a tres objetos:
mención especial. Esta implementación delega a su vez
en un objeto de tipo AuthenticationDao, un interfaz que
•
principal, típicamente un nombre de usuario.
•
credentials, las credenciales del usuario que
loadUserByUsername
prueban que es quien dice ser, normalmente su
información de un usuario a partir de su nombre de
contraseña, aunque podría ser otro tipo de
usuario. Acegi proporciona dos implementaciones de
información como certificados electrónicos.
este
•
define un objeto de acceso a datos con un único método
interfaz,
que
permite
InMemoryDaoImpl,
en
obtener
la
que
la
la
información de los usuarios se guarda en memoria, útil
authorities, un lista de los roles que posee el
para la realización de pruebas, y JdbcDaoImpl, que
usuario o grupos a los que pertenece.
accede a una base de datos a través de JDBC. Realizar
Cuando el usuario se autentica se crea un objeto
implementaciones de este interfaz es sumamente sencillo
Authentication, con los dos primeros objetos, principal y
y en el proyecto ONess [3] se encuentra disponible una
credenciales. En el caso de autenticación mediante
implementación
nombre de usuario y contraseña se creará un objeto
relacional Hibernate.
UsernamePasswordAuthenticationToken.
que
utiliza
el
mapeador
objeto-
Entre otras características que también se proporcionan
Acegi proporciona las clases necesarias para que esta
de forma transparente, tan sólo estableciendo unos
autenticación se realice mediante usuario y contraseña,
parámetros de configuración, son soporte para cifrado
utilizando
la
de contraseñas (SHA y MD5), caché de la información de
autenticación proporcionada por un contenedor de
autenticación y redirección automática de peticiones
aplicaciones como son catalina, jboss, resin o jetty, o
http a canales seguros https para aquellas urls que
utilizando el servicio de Single Sign On que proporciona
deseemos.
un
adaptador
para
enlazar
con
el proyecto CAS de la universidad de Yale [4].
Para el caso de aplicaciones web existen tres formas de
que un usuario se autentique:
Una vez creado este objeto Authentication se pasa al
AuthenticationManager, que a partir del principal y las
•
credenciales determina si éstas concuerdan con las
en el RFC 1945, el usuario introduce su usuario
esperadas, añadiéndole al objeto Authentication las
authorities correspondientes en caso
y contraseña en una simple ventana emergente
afirmativo o
del navegador. Es necesario en el caso de que se
lanzando una excepción de tipo AuthenticationException
quieran añadir características de seguridad a
en caso contrario.
servicios web.
Acegi proporciona una implementación del gestor de
autenticación AuthenticationManager
que debería ser
suficiente
de
los
casos,
el
tan
sólo
delega
la
para
ProviderManager.
Utilizando autenticación de tipo BASIC, definida
la
mayoría
Esta
clase
•
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.
•
autenticación en una lista de proveedores configurable,
Utilizando el servicio de autenticación central
interfaz
CAS de la Universidad de Yale [4], en caso de
AuthenticationProvider. Entre las implementaciones de
que se requieran características de Single Sign
proveedores
se
On, de forma que el usuario sólo tiene que
encuentran las necesarias para realizar la autenticación
autenticarse una vez para todos los servicios
contra varios servidores de aplicaciones (catalina, jboss,
que puedan proporcionarse en el ámbito de una
resin y jetty), contra un fichero de configuración JAAS,
empresa, incluso en distintos servidores y
contra CAS (la solución Single Sign On de la universidad
desarrollados
de Yale [4]), y contra un objeto de acceso a datos
programación.
cada
uno
usando
de
los
cuales
suministradas
implementa
con
el
DaoAuthenticationProvider,
el
proyecto
que
es
el
con
distintos
lenguajes
de
Cada una de las formas anteriores requiere de la
comúnmente usado puesto que es el que permite
configuración del filtro correspondiente en el descriptor
acceder a la información almacenada en una base de
de
datos.
aplicación
BasicProcessingFilter,
web,
AuthenticationProcessingFilter
o
CasProcessingFilter
respectivamente. La forma de configurarlos es definir los
80
Actas del II congreso javaHispano
•
filtros como del tipo FilterToBeanProxy, delegando,
RoleVoter, que comprueba que el usuario
según un parámetro de inicialización, en uno de los
presente un determinado rol, comprobando si
filtros anteriores definidos en el contexto de aplicación
se encuentra entre sus authorities.
de Spring, lugar donde pueden ser más fácilmente
•
configurados.
BasicAclEntryVoter, que a su vez delega en una
jerarquía de objetos que permite comprobar si
Los clientes llamados “ricos” o aplicaciones standalone
el usuario supera las reglas establecidas como
también están soportados, utilizando un gestor de
listas de control de acceso.
autenticación remoto cuya implementación utiliza un
servicio
web en
el
lado
del
servidor,
El primer caso es el más común, proporcionando una
utilizando
RemoteAuthenticationManager
autenticación basada en grupos o roles, donde se
y
permite el acceso si el usuario pertenece a alguno de los
RemoteAuthenticationProvider.
2
configurados como requeridos. En el segundo caso se
permite restringir el acceso a objetos a nivel de instancia,
Autorización
caso que será discutido más adelante.
Una vez el usuario está autenticado entra en juego la
En ambos casos el sistema que intercepta las llamadas
parte del sistema encargada de la autorización, con el fin
debe ser configurado. En el caso de las aplicaciones web
de permitir que el usuario acceda sólo a aquellos
se hará mediante la configuración de un filtro en el
recursos a los que tiene permiso. Para ello Acegi
fichero web.xml.
intercepta las llamadas a los objetos, utilizando proxies
Los posibles recursos que se pueden proteger son
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
aplicación web, FilterSecurityInterceptor.
métodos de determinadas clases o instancias, así como
•
acceso a urls.
•
finalizará permitiendo el acceso al recurso o lanzando
AccessDeniedException.
La
de
Spring,
utilizando
MethodSecurityInterceptor.
protegido se comienza una cadena de eventos que
excepción
métodos de objetos definidos en el contexto de
aplicación
Cuando se intercepta una petición a un recurso
una
urls, mediante un filtro en el descriptor de
cualquier
PointCut
definible
en
AspectJ,
mediante AspectJSecurityInterceptor.
cadena
comienza en un objeto de tipo AccessDecisionManager,
2 Autorización a nivel de instancia
mediante listas de control de acceso
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
Existen casos en los que la protección de las llamadas a
AccessDecisionManager que se basan en el concepto de
métodos no es suficiente, necesitando protegerse de
una votación, pero diferenciando las reglas de decisión:
•
•
distinta forma distintas instancias de una clase. Como
UnanimousBased: permite el acceso si no hay
ejemplo se puede pensar en un sistema de ficheros, en
votos negativos
los que cada archivo tiene distintos permisos, según si el
usuario que accede a ellos es el dueño del archivo,
AffirmativeBased: permite el acceso si un voto
pertenece al grupo del dueño o no cumple ninguna de
es afirmativo
•
las opciones anteriores.
ConsensusBased: permite el acceso si el número
Acegi proporciona en sus últimas versiones el soporte
de votos positivos es mayor o igual que el de
necesario para implementar seguridad basada en listas
negativos
de control de acceso. Las clases clave que se deben
conocer son
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
llamado y vota sobre si se debe permitir el
la facultad de emitir votos en objetos de tipo
AccessDecisionVoter.
Se
proporcionan
BasicAclEntryVoter obtiene las ACLs del objeto
acceso a él o no.
dos
implementaciones de éste último interfaz:
81
Actas del II congreso javaHispano
•
•
BasicAclAfterInvocationProvider
permite
autenticación
utiliza
por
tanto
denegar el acceso a un objeto después de que
DaoAuthenticationProvider, configurándose con una
el método se haya invocado, útil cuando no se
caché de usuarios basada en EHCache. Por comodidad
puede saber a priori.
no se ha activado el cifrado de contraseñas, acción que
puede realizarse con tan sólo descomentar la línea
BasicAclAfterInvocationollectionFilteringProvider
indicada. El gestor de autenticación ProviderManager
, similar al anterior, elimina los objetos a los que
tan sólo tendrá como proveedor el anteriormente
el acceso no ha sido permitido en aquellos
mencionado, ya que el único repositorio de usuarios será
métodos que devuelven colecciones.
la base de datos.
Para más detalles sobre ACLs se recomienda consultar el
En la aplicación web es necesario añadir dos filtros,
completo manual de referencia de Acegi.
2
se
Acegi Security System for Spring Http Session Integration
Filter, que hace que la información de autenticación esté
Ejemplo
disponible para sucesivas peticiones del usuario al
guardarla en la sesión, y Acegi Authentication Processing
Como ejemplo se utilizará el proyecto ONess [3],
subproyectos user-model y user-webapp.
Filter para procesar el formulario de login de un usuario.
En este
El primer filtro no requiere configuración, mientras que
proyecto se ha configurado una aplicación web para
el segundo la delega en el contexto de aplicación de
proteger sus recursos en peticiones http. Se han omitido
Spring,
partes no relevantes para este ejemplo, pero que pueden
definiendo
un
bean
authenticationProcessingFilter, donde se referencia el
ser consultadas en la página web y en el repositorio de
gestor de autenticación anteriormente configurado y la
código fuente del proyecto, entre otros la configuración
página a la que ir en caso de error en el login, entre
necesaria para utilizar autenticación basada en HTTP
BASIC o CAS o las clases necesarias para ejecutarlo.
otros, y authenticationProcessingFilterEntryPoint, donde
Acegi utiliza el contexto de aplicación de Spring para
de login.
se configura la página donde se encuentra el formulario
definir la configuración necesaria. Para aquellas personas
En cuanto a autorización, las decisiones se tomarán
que no están familiarizados con Spring decir que tan
sólo
es
necesario
crear
un
fichero
basándose en los roles del usuario utilizando RoleVoter,
/WEB-
y puesto que tan sólo existe ese AccessDecisionVoter no
INF/applicationContext.xml con el contenido que se
influirá el gestor de decisiones, optando por un
muestra en la Fig. 1 y añadir a /WEB-INF/web.xml el
AffirmativeBased.
contenido de la Fig. 2. En este segundo fichero se
configura
un
listener
que
procesa
el
primero
En la aplicación web se configurará un filtro Acegi HTTP
automáticamente cada vez que el contenedor de
Request Security Filter para restringir el acceso a
aplicaciones inicia la aplicación web, y unos filtros que
determinadas urls. Este filtro al igual que los anteriores
procesan todas las peticiones que llegan.
se configura mediante el contexto de aplicación de
Spring, donde se define un FilterSecurityInterceptor,
La autenticación se realiza a través de un objeto de
filterInvocationInterceptor,
acceso a datos DAO implementado con el mapeador
objeto-relacional Hibernate, authenticationDao, para
Como
proveedor
roles
ya está autenticado, y el punto de entrada, para el caso
también se incluye comentada la definición de un DAO
InMemoryDaoImpl.
los
enlazan el interceptor, para el caso en el que el usuario
base de datos. Como alternativa para realizar pruebas
tipo
define
y se define también securityEnforcementFilter, donde se
acceder a la información de usuarios almacenada en una
de
que
necesarios para acceder a las urls utilizando comodines,
contrario.
de
<?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 -->
82
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>
83
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>
<listenerclass>net.sf.oness.common.webapp.controller.listener.SpringContextLoaderListener</listen
er-class>
</listener>
<filter>
<filter>
<filter-name>Acegi Security System for Spring Http Session Integration Filter</filtername>
<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>
84
Actas del II congreso javaHispano
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</paramvalue>
</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</paramvalue>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Security System for Spring Http Session Integration Filter</filtername>
<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,
Agradecimientos
incluyendo autorización basada en listas de control de
A Ben Alex, principal desarrollador del proyecto Acegi,
acceso, y acceso remoto desde aplicaciones standalone.
por su colaboración.
8 Conclusiones
Referencias
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
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
una
línea
de
código.
Para
[2]
Spring Framework http://www.springframework.org.
[3]
ONess http://oness.sourceforge.net
[5]
utilizan ese magnífico framework, cuyo número crece día
ni
for
Spring
CAS (Central Authentication Service). Universidad de
Yale, http://www.yale.edu/tp/auth/.
funcionalidades de seguridad a las aplicaciones que
información se recomienda la lectura del
Acegi
Security
System
http://acegisecurity.sourceforge.net.
[4]
con Spring hace que sea el recomendado para añadir
modificar
[1]
mayor
manual de
referencia, realmente completo.
85
Weblog del autor http://www.jroller.com/page/carlossg
Actas del II congreso javaHispano
86
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
abraham@javahispano.org
es un software concreto, sino un conjunto de
Abstract
especificaciones que definen todas y cada una de las
tecnologías que componen la plataforma. Un análisis
La plataforma Java ha sido y es blanco de las críticas de
acerca de la libertad de la plataforma no puede
numerosos activistas de la comunidad del Software
Libre (SL)
basarse en la licencia de una, o varias, de las
por “no ser Software Libre”. Sin embargo
implementaciones de un subconjunto de estas
Java, a diferencia de otras alternativas, no es un
especificaciones, que es en lo que habitualmente la
software, sino un conjunto de especificaciones que
comunidad del SL basa sus críticas, sino que debe
definen una serie de tecnologías. Por ello carece de
analizar el proceso de creación y mantenimiento de
sentido juzgar si la plataforma Java es o no libre en base
las especificaciones que definen la plataforma Java.
a la licencia de algunas de las implementaciones de un
subconjunto de las especificaciones, principal base de
Esta
tarea,
creación
y
mantenimiento
de
las
las críticas de la comunidad del SL. Lo que deberíamos
especificaciones, es responsabilidad de un organismo,
plantearnos, dada su condición de especificaciones, es si
el
Java puede considerarse o no un estándar libre.
organización y funcionamiento básico se perfilará en
En este trabajo analizaremos el proceso de creación de
este trabajo. A continuación se estudiará si las
las
especificaciones
de
la
plataforma
Java
Java
Community
Process
(JCP)
[1],
cuya
especificaciones creadas por el JCP pueden o no
para
considerarse estándares libres. Para ello se tendrán en
determinar si Java es o no libre. Emplearemos en este
cuenta tanto los criterios de la comunidad del SL,
análisis tanto los criterios de la comunidad del SL,
creados bajo la dirección de Bruce Perens, como los
creados bajo la dirección de Bruce Perens, como los
criterios de la comunidad académica, definidos por
criterios de la comunidad académica. También se
Ken Krechmer. Irónicamente Java cumple con creces
discutirá la problemática relacionada con la licencia de
las implementaciones de referencia de la plataforma y
los primeros, pero falla en los segundos.
se propondrá una solución que busca un equilibrio entre
Finalmente,
los intereses de la comunidad del SL y de Sun
implementaciones de referencia (IR) parece ser tan
Microsystems.
importante para el moviendo del SL, se discute este
problema.
Keywords: Libertad de Java, estándares libres, Java
Community Process, Software Libre.
y
Se
dado
que
mostrará
la
que
licencia
el
miedo
de
a
las
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
1
código fuente del software sin restricciones, entran
Introducción
en conflicto con el principio básico de la plataforma
Determinar la libertad de la plataforma Java no es
Java: “escríbelo una vez y ejecútalo en cualquier sitio”
cuestión de analizar las licencias bajo las que se
(adaptación de “Write Once Run Anywhere”, WORA).
distribuye el conjunto de herramientas de desarrollo
Se mostrará que en la práctica no hay evidencias de
(JDK), o el entorno de ejecución (JRE) de Sun
que esta fragmentación pudiera producirse y se
Microsystems, principal fuente de críticas de la
propondrá una fórmula mediante la cual Sun podría
comunidad del SL hacia Java. La plataforma Java no
seguir manteniendo el control de Java a nivel
87
Actas del II congreso javaHispano
3
empresarial y cobrando royalties por estas tecnologías
(dos
ventajas
relevantes
de
Sun
sobre
sus
El Java Community Process
El Java Community Process [1] es el organismo que
competidores empresariales), a la vez que libera el
dirige,
código de las IR.
mediante
la
creación
de
nuevas
especificaciones y el mantenimiento de las ya
existentes, la evolución plataforma Java. El JCP define
2
su propio funcionamiento y las normas por las que se
¿Qué es la plataforma Java?
rige, normas que han ido evolucionando desde su
Hill Venners en su libro Inside the Virtual Machine [2]
creación en Diciembre de 1998. La versión actual del
afirma que Java está formado por cuatro piezas
JCP, y la que se describe en este documento, es la 2.6
diferentes: una especificación de un lenguaje de
[3].
programación; una especificación de un formato
El JCP es administrado por el Program Management
binario, los bytecodes; una especificación de una
máquina
virtual,
encargada
de
interpretar
Office (PMO), organismo formado por asalariados de
los
Sun Microsystems. Dos Comités Ejecutivos (CE) se
bytecodes; y un conjunto de librerías estándar. Sin
encargan de aprobar las modificaciones y extensiones
duda estos cuatro elementos definen el lenguaje de
programación Java.
de
Sin embargo, si Java ha alcanzado tanto éxito y
(ediciones empresarial y estándar, respectivamente,
difusión no es sólo gracias al lenguaje, sino también
de la plataforma), y el otro de las relacionadas con
al resto de la plataforma, que integra múltiples
J2ME (edición para pequeños dispositivos: teléfonos
tecnologías en su seno: tecnologías para el desarrollo
móviles, tarjetas inteligentes…). Cada uno de estos
de aplicaciones Web (Servlets, JSP, portlets, etc.),
comités está compuesto por 16 miembros con
aplicaciones empresariales (EJB, JTA, JCA, JMS, etc.),
derecho a voto, 5 elegidos mediante votación entre
aplicaciones para telefonía móvil (CLCD, CDC, OpenGL
los miembros del JCP, votación en la que participan
ES, etc.), tarjetas inteligentes (JavaCard), y un
todos los miembros del JCP. 10 son propuestos por el
inmenso sinfín de tecnologías que hicieron a Java
PMO,
único hasta hace tan sólo un par de años, cuando
balanceada” y “representación regional” [3]. Estos
apareció .NET.
miembros han de ser ratificados mediante votación
El fin de este trabajo no es sólo analizar la libertad del
pública. El miembro restante es un representante de
plataforma;
siguiendo
uno
relacionadas
los
encargado
con
criterios
de
J2EE
de
y
las
J2SE
“comunidad
Sun. En cada comité hay un segundo representante
lenguaje de programación, y/o del JDK distribuido por
de Sun, que ejerce la labor de presidente, pero que
Sun, sino de toda la plataforma en su conjunto. Por
ello, para nuestros objetivos,
la
especificaciones
no posee derecho a voto.
es más correcto
considerar que la plataforma Java está compuesta por
Convertirse en miembro del JCP es gratis para
un conjunto de especificaciones, que definen todas y
empresas
cada una de las partes de la plataforma, y una serie
implementan especificaciones de la plataforma con
de implementaciones de estas especificaciones. Sin
ánimo de lucro y pagan por ello a Sun), y para
duda, por ser la base sobre la cual se edifica el resto
personas que a título individual deseen formar parte
de la plataforma, las especificaciones del lenguaje,
del JCP. Las empresas no licenciatarias han de pagar
bytecode, máquina virtual, y de las librerías estándar
5000 $ por año. En el caso de organizaciones sin
juegan un papel protagonista, pero no son las únicas.
ánimo de lucro e instituciones académicas es un
licenciatarias
de
Sun
(empresas
que
comité formado por un miembro de Sun, un miembro
del
88
mundo
del
SL
o
del
mundo
académico,
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
individuo con o sin vinculación con el JCP puede
si pueden formar parte del JCP gratis, o han de pagar
estudiar, opinar y enviar realimentación sobre este
2000 $.
borrador
Las
incorporaciones
de
nuevas
tecnologías
a
al
grupo
de
expertos.
En
base
a
la
realimentación de la comunidad el grupo de expertos
la
realiza modificaciones, completa la especificación y
plataforma Java se realizan a través del JCP, mediante un
nuevamente hace pública una versión más madura de la
“Java Specification Request” [4] (JSR). Para crear un JSR
especificación, el “Public Draft”. Nuevamente cualquiera
se ha de explicar en un documento la necesidad de la
puede enviar realimentación a cerca de este documento,
nueva tecnología, o de modificación de una tecnología
y el grupo de expertos puede realizar cambios en base a
ya existente, y cómo afectará este cambio al resto de la
la realimentación.
plataforma. Aunque no es necesario, también es
recomendable proponer un grupo de expertos que se
Cuando se llega a un acuerdo en la especificación ésta
encargará de desarrollar el JSR, en caso de ser aceptado.
ha de ser ratificada por el CE correspondiente, mediante
Cualquiera, sea o no miembro del JCP, puede proponer
votación pública en la que necesita una mayoría simple
nuevos JSR. Uno de los dos CE del JCP, según el nuevo
de los votos emitidos. Si es ratificada pasa a una tercera
JSR afecte a J2ME o a J2SE/J2EE, analiza la propuesta y
fase, donde es toda la comunidad la que revisa y
decide si acepta o no la creación del JSR. Esta decisión se
comenta la especificación, mientras que el líder del
realiza mediante una votación pública, donde el nuevo
grupo de expertos se encarga del desarrollo de la IR y el
JSR debe obtener mayoría simple.
TC. Una vez que el grupo de expertos ha terminado su
trabajo éste, nuevamente, ha de ser aprobado por el CE
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
correspondiente
mediante
Finalmente
entra
se
en
una
votación
una
fase
pública.
cíclica
de
mantenimiento de la tecnología, fase también abierta al
define la nueva tecnología o modificación de una ya
público (ver Fig. 1).
existente, una implementación que prueba que la
tecnología es factible, denominada Implementación de
Hay una serie de JSR en los que Sun tiene privilegios
Referencia (IR), y un Test de Compatibilidad (TC), una
especiales y que se rigen por unas normas ligeramente
batería de pruebas que permite comprobar si una
diferentes: los “Umbrella Java Specification Request”
implementación cumple o no con la especificación.
(UJSR) [3]. Estos son los JSR que definen las tres
Tanto la IR como el TC son desarrollados bajo la licencia
ediciones de la plataforma: J2SE, J2EE, J2ME y los
que el líder del grupo de expertos decida, pudiendo
diversos
optar por cualquier licencia libre.
protegen, entre otros, la especificación de la máquina
perfiles
de
J2ME.
Estos
JSR
“paraguas”
virtual, el lenguaje, y el bytecode. Los cambios en estas
En una primera fase el grupo de expertos se centra en la
especificaciones pueden afectar a la compatibilidad hacia
definición la tecnología. Primero debe crear un borrador
atrás, o a la portabilidad, de las aplicaciones, por ello
de la especificación, “Early Draft”, que se publica en
Sun justifica este trato especial. Cualquier nueva
Internet y es accesible a todo el mundo; cualquier
89
Actas del II congreso javaHispano
funcionalidad o tecnología que quiera incorporarse a
libertad, tanto dentro del mundo del SL como en el
cualquiera de las tres ediciones de la plataforma ha de
académico, se emplea el término “estándares”. Cabe
hacerlo a través de un UJSR.
preguntarse qué diferencias hay entre una especificación
y un estándar; y si podemos juzgar a las especificaciones
Para que un UJSR sea aprobado debe obtener al menos 5
de la plataforma Java con los criterios de los estándares
votos positivos del CE correspondiente, y de los votos
libres. He aquí una definición de cada uno de estos
emitidos al menos dos tercios han de ser de aprobación.
términos:
Además el representante de Sun puede vetar la nueva
•
especificación, lo que se traduce en que Sun tiene la
Un estándar es una tecnología, formato o método
última palabra en lo que se refiere a la aprobación de los
desarrollado y adoptado a través de un proceso
UJSR, y por lo tanto a cambios sobre J2SE, J2EE y J2ME.
abierto de consenso, bajo la guía de cuerpos
nacionales (ANSI, BSI, ect.) o internacionales (ISO,
No todos los JSR se rigen por las normas aquí descritas;
IEEE, etc.) de estándares.
como ya se ha comentado el propio JCP es un JSR que
•
evoluciona y por lo tanto sus normas cambian. En un
Una especificación es un conjunto de documentos
principio no era tan abierto, no permitiendo, por
desarrollados por un grupo dentro de la industria,
ejemplo, la implementación de los TC e IR bajo licencias
pero sin guías o procedimientos formales que
libres. Sun también tenía derechos de veto sobre más
aseguren que el trabajo está abierto a cualquier otra
JSR, y las implementaciones de las especificaciones
parte interesada, o abierto para su revisión y
estaban obligadas a respetar las posibles patentes que
comentario durante el desarrollo (IETF, WC3, OMG,
hubiese en las especificaciones, obligación que ya no
etc.).
existe en la actualidad. Algunos JSR todavía se guían por
En algunas definiciones, como la aquí recogida, se exige
versiones anteriores del JCP, siendo el líder del grupo de
que un estándar esté aprobado por un organismo
expertos el que puede actualizar, si lo considera
reconocido oficialmente, un SDO (Standard Definition
conveniente, la versión del JCP. Es de esperar que según
Organization), mientras que en otras no se especifica el
estos JSR saquen nuevas versiones de mantenimiento se
tipo de organismo que debe reconocerlo. En otras
vayan pasando a la última versión del JCP, más abierta y
ocasiones sólo se le requiere que “esté creado a través
más respetuosa con el mundo del SL.
Finalmente,
cualquiera
puede
de un procedimiento abierto que garantice que se
implementar
las
escucharán toda las partes interesadas y se llegará a un
especificaciones, y distribuir su implementación bajo la
consenso”.
licencia que considere oportuno. No está obligado a
Las especificaciones del JCP se definen entre más de 700
pasar el TC, pero si desea hacerlo (esto es imprescindible
organizaciones e individuos, entre la cuales se hallan
si se desea emplear la marca registrada “Java” y términos
todas las grandes empresas de informática menos
relacionados), y ha realizado la implementación con
Microsof; están abiertas a todo el que las quiera
ánimo de lucro, ha de pagar a Sun por pasar el TC. Si la
examinar; cualquiera puede participar gratuitamente en
implementación ha sido realizada por una organización
el JCP, y por lo tanto en la definición y evolución de la
sin ánimo lucro, como suele ser el caso de los desarrollos
plataforma; e incluso sin pertenecer al JCP se puede
libres, el mismo comité de tres personas que decide si las
contribuir
organizaciones sin ánimo de lucro pagan por pertenecer
especificaciones.
al JCP, decide si ha de pagar o no por pasar el TC. No
pasar
el
TC
no
implementación
implica
no
que
cumpla
la
una
caracterizar
las
de
construcción. Por otro lado en la bibliografía sobre
estándares libres se trata a las especificaciones del JCP
como “estándares” [5].
El nombre que recibe la documentación que define las
forman
justo
de
posibilidad de participación sin discriminación en su
Estándares vs especificaciones
que
parece
definición
partes, con garantías de acceso, transparencia, y con
efectivamente la cumple.
tecnologías
No
de
bibliografía), a algo que es consensuado entre tantas
sin
embargo es una garantía para sus usuarios de que
3.1
proceso
“especificación” (al menos en el sentido de cierta
determinada
especificación,
al
la
plataforma
Java
Evitaremos entrar más en discusiones lingüísticas y, dado
es
el carácter consensuado y abierto de las especificaciones
“especificaciones”; sin embargo cuando se habla de
del JCP las trataremos como “estándares”, aún cuando
90
Actas del II congreso javaHispano
no estén reconocidas por organismos de estándares
implementación; esto último es casi imprescindible para
oficiales. El motivo principal para ello es la lentitud de la
el mundo del SL, que no puede permitirse pagar royalties
evolución de los estándares en los organismos oficiales.
por usar el estándar, ni afrontar largos y costos juicios.
En su día Sun consideró llevar a ISO las especificaciones
Un estándar libre respeta la libertad de elección:
del JCP, pero lo descartó porque ISO ralentizaría
podemos tomar hoy una decisión y mañana otra
demasiado la evolución de la plataforma: más de un
diferente: si desarrollamos una web con ASP .NET nos
estándar definido dentro de ISO u organismos similares
ataremos a un servidor web y a un sistema operativo. Si
se ha quedado obsoleto antes de llegar a ver la luz.
4
empleamos JSP o php podremos cambiar en cualquier
momento de servidor web, ya que hay múltiples
Importancia de los estándares libres
vendedores e implementaciones libres que los soportan,
La interoperabilidad, capacidad de un sistema para
y/o de sistema operativo.
trabajar con otro, es una de las características más
Incluso las más “pequeñas” estandarizaciones libres han
deseables para cualquier aplicación informática. De poco
permitido enormes avances. Por ejemplo, fueron los
nos valdría un cliente de correo que no siga el protocolo
estándares libres como TCP/IP, FTP, HTML, SMTP, etc. los
SMTP, un procesador de textos cuyos documentos sólo
que permitieron construir el único “caso de éxito”
se pudiesen visualizar y editar en la máquina donde se
auténtico en lo referente interoperabilidad: Internet. A
crearon, o un servidor web que no respeta el protocolo
principios de los años 90 en las redes empresariales
http. En el pasado era posible concebir un sistema
coexistían un conjunto de protocolos propietarios para la
informático que no interoperaba con ningún otro
comunicación en red entre las máquinas de distintos
sistema; sin embargo en la era de Internet, donde
fabricantes (IBM, Apple, Microsoft, VAX, ect.) entre los
proliferan múltiples aplicaciones distribuidas que son
accedidas
por
múltiples
dispositivos
de
cuales era difícil interoperar. En este contexto Internet se
diversa
abre a las empresas y trae consigo TCP/IP, un protocolo
naturaleza (PCs, PDA, terminales móviles de última
libre para la comunicación en red, y un conjunto de
generación, mainframes…) no hay lugar para este tipo
protocolos libres para interoperar entre equipos (FTP,
de islas.
Telnet, ect.). No le llevó mucho tiempo imponerse a los
otros protocolos propietarios siendo clave en su triunfo
El software libre por sí sólo no genera interoperabilidad;
la apertura del estándar, y el no tener que pagar ningún
los estándares son la base para conseguirla. De aquí la
enorme importancia de contar con estándares libres,
tipo de royalties para emplearlo.
para invitar que estándares propietarios coarten la
Un estándar libre fomenta la aparición de múltiples
libertad del software, aún cuando su código fuente sea
implementaciones de características heterogéneas, libres
libre. Los estándares propietarios, o el no uso de
y comerciales. Esto beneficia al usuario final, ya que se
estándares, es un mecanismo para entorpecer e incluso
evita el “vendor lock-in”, quedar atrapado por un
anular el desarrollo de soluciones de terceros (en especial
proveedor del que dependo por haber basado mi
las libres). Así por ejemplo los desarrolladores de
solución en su producto.
OpenOffice se ven obligados a hacer reingeniería inversa
Tras estos argumentos cabe hacerse una pregunta:
para acceder a los formatos OLE de Microsoft, y se
¿Hasta que punto es “libre” un software cuyo código
exponen a ser demandados por sus actividades. De un
modo
similar
los
desarrolladores
de
clientes
fuente es libre pero que implementa un estándar
de
propietario? Podremos modificar su código fuente, pero
mensajería libres que interactúan con la red MSN cada
lo hacemos siempre dentro de la jaula (formato o
vez que surge una nueva versión del protocolo MSNpX
protocolo) que define el estándar propietario, que no
deben reventarlo y actualizar los clientes; y Microsoft
controlamos y al que estamos obligados a ceñirnos.
podría cerrar la red de MSN, impidiendo que clientes de
terceros, libres y no libres, se conecten a su red.
Podría darse el caso de que el dueño del estándar
Un estándar libre debe poder implementarse libremente.
producto libre. Un software “libre”, en el sentido más
propietario ponga trabas, o impida, el desarrollo del
Para ello su contenido ha de ser público y accesible,
eliminando
las
barreras
de
tipo
técnico
en
general de la palabra, debe basarse en estándares libres.
la
implementación. Tampoco deben existir barreras de tipo
económico o legal (patentes y copyright) que impidan su
91
Actas del II congreso javaHispano
4.1
¿Qué es un estándar libre?
Los criterios sobre los que trabaja Perens constituyen el
intento más serio y consensuado de la comunidad del SL
Dentro de la comunidad del SL no hay una definición
para definir qué es un estándar libre, por ello los
globalmente aceptada sobre qué es un estándar libre.
emplearemos como base del análisis que realizaremos.
Así, por ejemplo, ni Free Software Foundation (FSF) [6],
No obstante en este estudio añadiremos algunas ideas
ni Open Source Iniciative (OSI) [7] proporcionan criterios
del trabajo de Krechmer a los criterios de Perens, por
bien definidos para determinar si un estándar es o no
considerar que éstas los complementan.
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
5
¿Está la plataforma Java compuesta
por estándares libres?
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
En este apartado analizaremos el proceso de creación y
manifiesto “Open Source Definition”. Actualmente hay
mantenimiento de los JSR así como las condiciones bajo
un borrador con el trabajo realizado hasta la fecha en
las cuales se puede acceder a ellos e implementarlos,
[8].
para determinar si Java puede o no considerarse un
estándar libre.
Otro trabajo interesante es el de Ken Krechmer, “The
Principles
of
Open
Standards”
[9].
Krechemer,
a
Criterios de Perens
diferencia de Pernes, no es un activista del Software
5.1
Libre. Su trabajo está orientado a organizaciones
El borrador creado por Pernees [8] en colaboración con
sensiblemente diferentes del JCP, como ISO o ECMA, que
el entorno de Debian define una serie de requerimientos
también estandarizan objetos materiales y tangibles, y
que debe cumplir un estándar para considerase un
no sólo software, algo que se puede replicar y trasladar
“estándar libre” (open standard). Además identifica una
de un punto a otro del planeta a coste prácticamente
serie de buenas prácticas, a modo de recomendaciones,
cero. Por ello no todas las ideas que hay tras los criterios
para los estándares libres, buenas prácticas que no se
de Krechemer poseen sentido en el mundo de lo
exigen para poder considerarse como libre. Analizaremos
intangible. Sin embargo hay algunas ideas que sí
punto por punto cada uno de los requerimientos
podemos tomar prestadas, ideas que no están presentes
descritos
entre las de Perens y que, desde el punto de vista de
subsecciones el contenido en cursiva es un resumen, que
autor, son de gran importancia en la definición de qué es
no una traducción, del contenido de cada uno de los
un estándar libre; dicho de otro modo: son carencias del
puntos del documento de Perens.
en
este
documento.
En
las
siguientes
borrador de Perens.
5.1.1
Al margen de estos trabajos existen varios portales
dedicados a los estándares libres, pero ninguno de ellos
Disponibilidad:
Un estándar libre debe estar disponible para leer e
define de un modo concreto y preciso qué es un
implementar por cualquier individuo u organización. Se
estándar libre, y se hallan muy lejos de tener un peso
recomienda como buena práctica que la documentación
equivalente a que FSF u OSI tienen sobre el SL.
y la IR del estándar estén disponibles en Internet. No se
OpenStandards.org [10] es una web creada a principios
hace ninguna referencia a la licencia del código fuente
del 2000 con un propósito no muy claro y que en la
de la IR.
actualidad está abandonada, sin que nunca haya tenido
actividad real. OpenStandards.net [11] es un escaparate
La documentación de cualquier JSR está disponible en
de noticias de otros sitios web y un almacén de enlaces
Internet,
que carece de contenidos propios. Mención a parte
implementarlo. En cuanto a la IR de referencia de un JSR,
merece Free Standards Group [12], dedicado a crear
y su test de compatibilidad, son siempre accesibles de un
estándares para el mundo Linux. Poseen certificaciones
modo gratuito para un individuo u organización sin
de gran reconocimiento, como LSD (Linux Standard
ánimo de lucro.
Base), OpenI18n, OpenPrinting, etc. Sin embargo sus
interesantes objetivos, crear estándares para Linux, no
coinciden con los que se persiguen en este trabajo.
92
y
cualquiera
puede
descargársela
e
Actas del II congreso javaHispano
5.1.2
Maximizar la elección del usuario final
5.1.4
No discriminación:
Los estándares abiertos deben generar un mercado
No se puede favorecer a ninguna implementación sobre
competitivo
otras: la certificación ha de ser justa y sólo basarse en
permitiendo
un
amplio
rango
de
implementaciones, con precios que varíen “desde muy
motivos tecnológicos.
altos a nulos”.
En la actualidad sólo se tienen en cuenta motivos
Evitar el “vendor lock-in” es uno de los principios básicos
tecnológicos para pasar los TC. Esto no fue así hasta
sobre los que se ha construido la plataforma, así como
hace unos meses, cuando entró en vigor JCP 2.6; hasta
una de sus principales ventajas frente a otras tecnologías
entonces una implementación libre de un UJSR no podía
propietarias. En la práctica, efectivamente podemos
certificarse por el tipo de licencia de su código fuente.
encontrar costosas implementaciones empresariales de
las especificaciones (Ej.: BEA WebLogic, IBM WebSphere
5.1.5
~100.000 $ por CPU) e implementaciones libres
Los estándares libres se pueden extender u ofrecer en
completamente gratuitas (Ej.: JBoss, JOnAS, Gerónimo).
5.1.3
Extensión o subconjunto:
subconjunto, aunque en este caso puede negarse la
certificación.
Sin Royalties:
Es posible implementar subconjuntos, superconjuntos, o
Debe ser posible implementar una especificación sin
modificaciones de las especificaciones del JCP; por
pagar royalties. Para garantizar que esto será siempre así
ejemplo en [14] se recogen múltiples variaciones del
(evitar posibles patentes submarinas) cualquier patente
lenguaje
incluida en el estándar debe poderse implementar de un
Java,
bytecode
y/o
JVM,
normalmente
desarrolladas con fines científicos. En general no es
modo totalmente libre de royalties. Perens acepta que la
posible certificar subconjuntos ni modificaciones de las
certificación del estándar pueda requerir pagar, y
especificaciones, aunque sí superconjuntos de ciertas
recomienda (aunque no exige) proporcionar un camino
especificaciones.
para la auto-certificación.
Así,
por
ejemplo,
los
distintos
vendedores de servidores de aplicaciones J2EE suelen
Todas las patentes involucradas en un JSR deben
extender la especificación con características propias
“garantizar
para diferenciar sus productos de los de la competencia.
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]
5.1.6
a quien las implemente.
Defensa contra prácticas predatorias
Este punto es una concesión más que un requerimiento.
La certificación de compatibilidad requiere pagar cuotas
Los
a Sun, pero los TC son accesibles gratuitamente para
modificaciones por parte de terceras partes para evitar
individuos y organizaciones sin ánimo de lucro [13], por
prácticas “embrace-and-extend”. Este tipo de prácticas
lo que es posible auto-certificarse. Además existe un
las suele llevar a cabo el vendedor predominante de un
camino
de
estándar, el cual crea una extensión del estándar no
implementaciones libres y sin ánimo de lucro: el servidor
compatible con el original e impide mediante patentes y
de aplicaciones J2EE JOnAS se certificó completamente
copyright que los demás vendedores implementen estas
gratis, y Geronimo lo hará en breve en las mismas
extensiones. Esto provoca que las implementaciones de
condiciones.
los demás vendedores no sean compatibles con las del
para
la
certificación
gratuita
estándares
libres
pueden
protegerse
contra
vendedor predominante y permiten a éste último crear
El código de la IR (y del TC) debe estar disponible bajo
un monopolio sobre el estándar.
condiciones RAND (Reasonable And Non Discriminatory)
[10], o más permisibles, para basar en ella otras
Dentro de los JSR, o del JCP, no se identifican defensas
implementaciones.
las
contra ese tipo de prácticas. No obstante la certificación
condiciones RAND en la práctica pueden no ser
de las implementaciones, así como la propiedad de Sun
razonables y sí suelen ser discriminatorias; sin embargo
de la marca “Java” y términos relacionados, que sólo se
que el código esté disponible bajo condiciones no más
pueden
restrictivas que RAND es mejor que ningún tipo garantía.
plataforma de estas prácticas. Esto es lo que sucedió en
Como
se
discute
en
[5]
emplear
tras
certificarse,
defienden
a
la
1998 con la JVM de Microsoft [15], que no seguía la
93
Actas del II congreso javaHispano
especificación de J2SE, por lo que Sun llevó a la
requerimientos. Veamos cuales son los requerimientos
compañía de Redmon a los tribunales.
añadidos.
5.2
5.3.1
¿Se cumplen los criterios de Perens?
Apertura:
El draft de Perens es el intento más serio y consensuado
Todas las partes interesadas pueden participar en el
que la comunidad del SL ha realizado para definir qué es
desarrollo del estándar.
un
estándar
libre.
Como
se
ha
mostrado,
las
Cualquier individuo puede formar parte del JCP, ya bien
especificaciones de la plataforma Java cumplen todos los
requerimientos
de
sea a título personal o como representante de una
este borrador, todas sus buenas
empresa u organización. En el caso de las organizaciones
prácticas y en varias ocasiones incluso van más allá, por
sin ánimo de lucro e individuos esta participación es
ejemplo, ofreciendo una certificación completa gratuita
completamente gratuita. Por otro lado, incluso sin
a implementaciones sin ánimo de lucro.
participar en el JCP se puede participar en la definición
En base a los criterios de Perens la plataforma Java, un
de un único JSR, e incluso
conjunto de especificaciones que definen una serie de
involucrado en el JCP, o en uno de sus JSR, cualquiera
tecnologías, es libre. Esto no quiere decir que todas las
puede acceder a la documentación de todos los JSR
implementaciones de cada tecnología se distribuyan bajo
mientras se están desarrollando, y enviar realimentación
una
al grupo de expertos.
licencia
libre,
pero
la
licencia
de
las
sin estar directamente
implementaciones nada tiene que ver con la libertad del
estándar; de hecho Perens nunca la menciona en sus
criterios.
5.1.6
Estos requerimientos no son suficientes, desde el punto
En el proceso de definición del estándar todos los
de vista del autor, para considerar un estándar libre.
intereses son discutidos y se llega a un acuerdo sin
Podrían definir un estándar “accesible”: puedo acceder a
dominación. Una votación puede ser empleada para
él e implementarlo libremente, pero esto no es
encontrar una solución.
suficiente: la única libertad que se garantiza es la de
Consenso y proceso de decisión justo:
Todos los intereses y contribuciones de las distintas
seguir un camino (el marcado por el estándar) que
partes son considerados y discutidos en el JCP, y la
podría haber sido definido por una sola parte interesada
votación, de los CE, es la que finalmente decide qué se
(empresa, organización o individuo), y no por todas las
incorpora y qué no se incorpora a las especificaciones
partes interesadas. Por ello, para completar este estudio,
añadiremos dos criterios del documento de Krechmer a
que forman la plataforma.
los definidos por Perens.
Sin
embargo
siempre
hay
un
miembro
de
Sun
Microsystems en cada CE, que tiene derecho de veto
5.3
Criterios de Krechmer
sobre todos los UJSR, y de los restantes 15 miembros 10
son propuestos por Sun, aunque deben de pasar una
Krechmer, a diferencia de Perens, es un investigador del
ratificación pública. El PMO, aunque es un mero órgano
laboratorio de Palo Alto, en California, USA. Su trabajo
administrativo, está compuesto por asalariados de Sun, y
ganó un premio en la competición “World Standards
siempre hay un miembro de Sun en el comité de tres
Day” de 1998 y fue publicado en la revista Standards
personas que decide si una organización sin ánimo de
Engineering. Este trabajo aborda la problemática de los
lucro puede o no pertenecer gratis al JCP o pasar el TC
estándares en general, no sólo informáticos, y se escribió
sin pagar. Este criterio no se cumple por los privilegios
pensando en organizaciones muy diferentes del JCP,
de uno de los participantes en el proceso de definición
como ISO o ECMA, que también estandarizan objetos
de las especificaciones: Sun Microsystems
materiales, y no sólo software. Por ello no todas las ideas
que hay tras los criterios académicos poseen sentido en
La solución a esta falla podría pasar por la gestión del
el mundo de lo intangible, y algunos requieren cierta
JPC por un organismo independiente, estilo Apache
adaptación.
Software Foundation. Esto evitaría que la plataforma se
mueva en una dirección que no es la más conveniente
No obstante, en líneas generales, los criterios de
para todas las partes interesadas, por causa de los
Krechemer incluyen a los de Perens y añaden más
94
Actas del II congreso javaHispano
intereses particulares de una empresa. Todos los
lenguaje de programación en Sourceforge, estando muy
miembros de los CE deberían elegirse de un modo
cerca de de los primeros, C y C++; y existen una gran
democrático y debería desaparecer el derecho de veto.
cantidad de implementaciones libres de especificaciones
Java, suficientes para construir una compleja y completa
solución empresarial [21].
6
Implementaciones de Referencia y
Software Libre
Cabe preguntarse porqué siendo la comunidad Java una
de
las
más
prolíficas
desarrollando
SL
las
Resulta evidente que la comunidad del SL se beneficiaría
implementaciones libres del entorno base van tan lentas.
de poseer un código libre en el que basar sus
La respuesta posiblemente sea que esta prolífera
implementaciones de las especificaciones, y es deseable
comunidad,
que este código fuese el de las propias IR. Por un lado
implementaciones gratuitas del entorno base que
éstas son la primera implementación que se desarrolla, lo
poseen una calidad contrastada, prefiere centrarse en
que permitiría a la comunidad del SL disponer del código
desarrollar aplicaciones de más alto nivel, como librerías,
base rápidamente. Por otro, si las todas las IR fuesen
aplicaciones de escritorio, servidores de aplicaciones, etc.
libres serían testadas por multitud de desarrolladores, lo
que tienen un beneficio comparativo mucho mayor para
que redundaría en una mejora de su portabilidad y su
la sociedad. No obstante esta situación podría cambiar
calidad, y por consiguiente en la portabilidad y calidad
en breve, debido a la intención del gobierno de Brasil de
de las demás implementaciones: Jason Hunter afirma
desarrollar una implementación libre de J2SE [21], que
que desde que Tomcat es la IR de los motores de Servlets
esperan tener lista para finales del 2005. De cumplirse
se han eliminado muchos bugs de portabilidad en los
este objetivo el año 2005 podría ser el año en que la
motores comerciales.
comunidad del SL deje a un lado sus reparos y abrace
dado
que
dispone
de
varias
definitivamente a la plataforma Java.
La licencia de las IR desarrolladas por Sun son la principal
fuente de críticas a Java por parte del mundo del SL. Sin
La IR del J2SE, así como otras IR desarrolladas por Sun,
embargo, como hemos mostrado, Java no es un
se distribuyen bajo licencia Sun Community Source
software, sino un conjunto de especificaciones. Alguna
License (SCSL) [22]. Esta licencia permite ver el código
de las implementaciones de estas especificaciones son
fuente del desarrollo, e incluso modificarlo, pero sólo
libres, otras no, pero esto no guarda relación con la
bajo ciertas condiciones, las cuales, en esencia, fuerzan a
libertad de las especificaciones. Decir que Java no es libre
que el producto modificado siga cumpliendo las
porque
una
especificaciones de la máquina virtual, bytecode y
especificación no licencia su código fuente mediante una
lenguaje Java. Su objetivo es evitar que la plataforma se
licencia libre es tan incoherente como decir que el
fragmente
protocolo http no es libre porque Internet Explorer e
compilador o máquina virtual no compatibles con las
Internet Information Server no son libres.
especificaciones. Sun afirma que esta licencia “toma las
una
de
las
implementaciones
de
por
causa
de
implementaciones
del
ventajas de los modelos de código abierto y propietarios,
La IR más polémica es sin duda la de J2SE. Efectivamente
y elimina sus inconvenientes” [22], ya que permite
la implementación de Sun no es libre, ni la de IBM,
acceder al código fuente libremente, con todos los
BlackDown, Bea, etc. Sin embargo Kaffe [16], GCJ [17],
beneficios que para la comunidad y para la propia
GNU Classpath [18], Japhar [19], Jikes [20], etc. sí son
plataforma conlleva, siempre que el acceso no atente
libres, si bien es cierto que ninguna de ellas tiene en la
contra el principio básico de WORA.
actualidad una funcionalidad suficiente para resultar
atractiva a los desarrolladores. En este sentido es la
Sin embargo, una vez que un individuo ha accedido al
propia comunidad del SL quien, por la causa que fuere,
código licenciado SCSL esta licencia le impide participar
está fallando a la hora de proveer una alternativa libre a
en proyectos de código abierto, ya que el código que ha
este estándar, del mismo modo que esta comunidad ha
visto es propiedad intelectual de Sun y no puede
creado alternativas libres para otros estándares (Mozilla
emplear en proyectos libres lo que en él ha aprendido.
y Apache web server en el caso de http, por ejemplo).
Además, si desea cobrar a sus usuarios por el trabajo que
ha realizado está obligado a pagar cuotas a Sun.
En general el SL goza de un excelente estado de salud en
Evidentemente una licencia así dista mucho de poder
la plataforma Java: a pesar de ser un lenguaje de
programación
relativamente
reciente
es
el
considerarse libre.
tercer
95
Actas del II congreso javaHispano
¿Es necesaria una licencia de este tipo para algunas IR,
comiendo el terreno de los servidores SPARC y Solaris.
para proteger a la plataforma Java de la fragmentación?
Sun con Solaris10, un sistema operativo de código libre
Es una pregunta difícil de responder. Sun afirma que sí;
que sale al mercado con una agresiva campaña de
sin ella algunas empresas podrían aprovecharse de su
precios que intenta competir con los servidores Linux de
posición privilegiada en el mercado para imponer una
RedHat, junto con la venta de hardware de bajo precio
versión
no
basado en la arquitectura x86, va a tratar de cambiar
compatible con las demás. Este fue el caso de Microsoft,
esta tendencia; pero el éxito de su nueva estrategia no
quien en su día desarrolló una versión de la máquina
está garantizado.
de
la
máquina
virtual
devaluada,
o
virtual y herramientas de desarrollo que permitían
En
acceder a ciertos servicios de Windows, lo que daba
respuesta
a
esto
Sun,
una
compañía
que
tradicionalmente vivía del hardware, está apostando
lugar a crear aplicaciones que sólo funcionaban en este
fuertemente por los negocios basados en el software y
sistema operativo [15]. Si la plataforma Java hubiese sido
los servicios. El centro del negocio del software en Sun es
completamente abierta nada hubiese podido detener a
Java: recientemente hemos visto como Sun ha cambiado
Microsoft. Hoy en día la plataforma estaría fragmentada;
el nombre de varios de sus productos para incluir el
más de la mitad de los desarrolladores Java desarrollan
nombre Java en ellos: Java Entreprise System, Java Studio
bajo Windows, y probablemente buena parte de ellos
Creator, Sun Java System Application Server, Java
emplearían las herramientas de Microsoft. Según Sun
Desktop System. En el último la palabra Java se incluyó
SCSL vela para que esto no suceda.
en el nombre sólo como marketing, ya que Java Desktop
Sin embargo Microsoft, u otra gran empresa, y la
System es un S.O. de escritorio basado en Linux que
comunidad de SL tienen recursos suficientes para
poco tiene que ver con Java. Menos aún tienen que ver
implementar
sin
las Sun Java Workstation, unas estaciones de trabajo con
necesidad de basarse en ningún código. Es posible partir
la
máquina
virtual
desde
cero,
procesadores Opteron que no incluyen ningún tipo de
de las especificaciones del lenguaje y máquina virtual
optimización para Java.
[24, 25] e implementar una variante de Java sin basarse
Por otro lado, Sun actualmente obtiene una cantidad de
en ningún código, con lo que esta licencia pierde
ingresos considerable por las licencias de las tecnologías
bastante sentido.
Java; y su control sobre Java puede ayudarle a
Por otro lado no hay ningún indicio de fragmentación
posicionarse en un mercado emergente que a medio
dentro de la comunidad del SL: las implementaciones
plazo alcanzará un notable volumen: J2ME. Esto sin
libres de J2SE (y de cualquier otro JSR) siempre tratan de
olvidar el prestigio que le da a la compañía haber creado
adherirse a las especificaciones.
y controlar la que actualmente es la principal tecnología
para crear aplicaciones de servidor y para dispositivos
Sun a menudo alega que las múltiples distribuciones de
móviles.
Linux prueban la comunidad del SL no es capaz de
reconocer que hay cosas que si se bifurcan pierden su
Siendo razonable, las empresas no son ONGs, no es
valor. Sin embargo parece que Sun se olvida del
lógico que Sun desperdicie su posición ventajosa,
tremendo esfuerzo que esta comunidad realiza a través
respecto a sus competidores y no explote una tecnología
de Free Standards Group [12] para lograr que todas las
en la que ha invertido tanto. A primera vista parece que
distribuciones de Linux, y otros sistema operativos *nix,
el mundo del SL busca un control sobre Java que
sigan una serie de estándares que garanticen la
probablemente Sun no se pueda permitir ceder en este
compatibilidad
momento sin dañar gravemente sus intereses.
comunidad
entre
distribuciones;
y
es
que
la
del SL sabe reconocer y respetar ciertas
Desde el punto de vista del autor existe un punto de
cosas qué no se deben fragmentar.
encuentro entre Sun y la comunidad del SL, que puede
En la práctica no hay indicios de que liberar el código
permitir al primero seguir controlando Java a nivel
fuente de las IR suponga un riesgo de fragmentación
empresarial, y al segundo disponer del código fuente de
para la plataforma. Desde el punto de vista del autor lo
las IR. Este punto de encuentro es licenciar el código
que realmente detiene a Sun es un problema de
SCSL mediante una doble licencia [26]. Un software que
naturaleza muy diferente: Sun, como empresa, necesita
se distribuye mediante una doble licencia se libera bajo
Java, y necesita controlar Java a nivel empresarial. Las
dos licencias, una libre con un “copyleft” [27]
plataformas Intel y compatibles, junto con Linux, están
fuerte (GPL o similar) y una propietaria. La libre satisfaría
96
muy
Actas del II congreso javaHispano
todas las demandas del mundo del SL, sin embargo no
incluso
sería aceptable, en general, para las empresas: éstas
gratuitamente, un rechazo frontal a cualquier patente no
verían su código infectado por el efecto “virus” de la
licenciada Royalty Free en los JSR, y una auto-limitación
licencia con copyleft y tendrían que liberar su propio
de los privilegios de Sun.
se
incentiva
dando
opción
a
certificarse
desarrollo bajo una licencia libre. Dado que muy pocas
empresas estarán dispuestas a ello se verán obligadas a
7
optar por la licencia propietaria, y de este modo Sun
seguiría obteniendo beneficios y controlando Java a nivel
Conclusiones
La plataforma Java, un conjunto de especificaciones que
empresarial.
definen una serie de tecnologías, según los criterios
Al mismo tiempo Sun gana el apoyo de la comunidad del
recogidos en el borrador de Perens, principal esfuerzo
SL y garantiza que toda distribución de Linux incluya
del mundo del SL para definir qué es un estándar libre,
una JVM. A su vez la comunidad del SL obtiene un
es libre. En este análisis las licencias de las IR, u otras
valioso código en el cual basar sus desarrollos; dejaría de
implementaciones, carecen de relevancia; de hecho
tener reticencias sobre si algún día Sun empieza a cobrar
nunca se mencionan estas licencias en el documento de
por Java o cambia sus condiciones de distribución; y
Perens. Extendiendo estos criterios del modo que al
tendría garantías de que Java no se vería afectado por
autor le ha parecido adecuado, se identifica un
una hipotética opa hostil, o cualquier otra adversidad,
problema: los privilegios que Sun posee sobre el JCP. A
que pueda padecer Sun y hacer que la propiedad
pesar de ello no hay constancia de que Sun los haya
intelectual relacionada con la plataforma Java cambie de
empleado con otro fin distinto de velar por la
dueño.
plataforma.
Liberar el código SCSL bajo una doble licencia (SCSL y
6.1
Unas palabras a favor de Sun
GPL, por ejemplo) beneficiaría tanto al mundo del SL
como a Sun. Haría que Java fuese mejor acogido y
Sun a lo largo de los años ha mostrado, tanto
tuviese más apoyos dentro de la comunidad del SL, con
verbalmente como con sus acciones, que sus privilegios
los consecuentes beneficios para la plataforma, y por
sobre la plataforma Java son para hacer frente a ataques,
extensión para Sun; habría más desarrollos libres en y
como sucedió en el caso de Microsoft, y no poner trabas
para Java; y el código de las IR estaría más chequeado, lo
al desarrollo de SL en la plataforma Java. Durante mucho
que incrementaría la portabilidad y fiabilidad de las IR y
tiempo Apache violó las normas del JCP, pudiendo haber
de todas las implementaciones que se basan en ellas.
sido demandada por Sun. Lejos de ocurrir esto Apache
mantenía una excelente relación con Sun, quien le
Por su parte Sun seguiría controlando y obteniendo
apoyaba y financiaba sus desarrollos libres, y todos los
beneficios de Java a nivel empresarial, ya que la mayor
problemas se zanjaron modificando el JCP para legalizar
parte de las empresas no optarían por la licencia libre
las actividades (desarrollo de una IR y TC bajo licencias
por su efecto vírico. Sun podría ganar el apoyo del
libres) que Apache llevaba tiempo realizando, pero que
mundo del SL sin perder su posición privilegiada en el
de
mercado Java.
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
Agradecimientos
portabilidad de la plataforma.
Deseo expresar mi agradecimiento a Alvaro-Sánchez
También es evidente que Sun empuja cada vez más la
Mariscal, Alberto Molperceres y Martín Pérez. Sin los
plataforma Java hacia la liberación: cada nueva versión
trabajos que vosotros realizasteis antes que el mío, sin
del JCP “libera” un poco más la plataforma. El JCP ha
las
ido evolucionando desde un estado en el que no era
realimentación que he recibido de vosotros este trabajo
posible realizar IR bajo licencias libres, los JSR podían
probablemente nunca habría visto la luz.
contener patentes y Sun poseía notables privilegios,
hasta una tolerancia total con el mundo del SL, al cual
97
discusiones
que
hemos
mantenido
y
sin
la
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
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.
Standars,
[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,
124.ibm.com/developerworks/oss/jikesrvm/
http://www-
[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=673049
882
[23] Sun
Community
Source
License
http://www.Sun.com/software/communitysource.
(SCSL),
[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
http://www.gnu.org/copyleft/copyleft.html.
copyleft?
98
Actas del II congreso javaHispano
Caso de uso: Empleo de tecnologías J2EE para el desarrollo
de una plataforma
Rafael Pedraza Carmona
Alberto Planas Domínguez
Antonio Navarro González
rpedraza@properly.es
SEIRC/CESEAND
aplanas@bic.es
navarro@properly.es
Benjamín de la Fuente Ranea Jose David Fernández Rodríguez
josedavid@properly.es
benjamin@properly.es
pertenecen al Departamento de Desarrollo. Los primeros
Abstract
productos se realizaron exclusivamente con tecnología
de Microsoft (Visual Basic for Applications); si bien al
En esta presentación se pretende explicar la experiencia
principio nos beneficiamos de la facilidad y simplicidad
que ha supuesto el desarrollo de una plataforma para la
de esta tecnología, pronto nos vimos en un callejón sin
gestión de ofertas y demandas tecnológicas, desarrollada
salida:
para dos organismos dependientes de la Consejería de
acorralados
por
unas
necesidades
y
especificaciones crecientes en complejidad y al mismo
Innovación, Ciencia y Empresa de la Junta de Andalucía. El
tiempo limitados por unas herramientas que no nos
objetivo principal de esta plataforma es servir de nexo de
proporcionaban
unión entre aquellas empresas, grupos de investigación u
soluciones
cuando
pretendíamos
obtener algún resultado más allá de los casos de uso
otros organismos que ofrecen algún producto con marcado
más
carácter innovador y aquellas otras que pueden ser
simples.
Problemas
de
escalabilidad
y
la
obsolescencia de la tecnología empleada no nos deja
consumidores de estas tecnologías.
otra alternativa que pegar el salto tecnológico.
Las características más reseñables de este proyecto son el
A la hora de tomar la decisión de hacia donde mover
uso en exclusiva de tecnologías de código abierto, el
nuestro marco de desarrollo los factores determinantes
empleo de las especificaciones J2EE para el módulo de
para elegir J2EE y software libre, fueron razones
servidor (basado en JBoss, Tomcat, Axis, Lucene,...), el
económicas (soluciones de Oracle, IBM y BEA son
innovador sistema de seguridad que facilita el acceso
excesivamente caras en un principio) y tecnológicas
segmentado a la información, un workflow para el control
(posibilidad de acceder al código y modificarlo, creciente
de distintos grupos de trabajo y el desarrollo de una
interface de cliente Java basado en la plataforma Eclipse 3.
madurez
La conjunción de todas estas tecnologías, con el lenguaje
aplicaciones de servidor y de cliente, presencia de J2EE
Java como hilo conductor, puede suponer un importante
en la industria frente a otras soluciones).
punto
de
referencia
para
otros
desarrolladores
de
desarrolladores,
que
la
tecnología,
Java
como
masa
lenguaje
crítica
común
de
para
Esta apuesta de futuro tenía que como consecuencia el
pretendan alcanzar un alto nivel tecnológico, basándose
destinar
para ello en la potencia y seguridad que aportan los
recursos
en
tiempo
y
económicos
a
desarrollos de código abierto.
investigación, partida para la que hasta ese momento no
Keywords: J2EE, JBoss, JavaCC, Eclipse, Lucene, Hylafax,
Software Libre, Seguridad.
2 Nuestro primer cliente: descripción del
proyecto
había existido presupuesto.
Gracias a nuestro trabajo de investigación durante más
1
de un año, tenemos la opción de presentar una oferta al
Salto tecnológico con software libre
Instituto de Fomento de Andalucía para el desarrollo de
Properly Software cuenta en la actualidad cuenta con
una
una plantilla de diez personas, de las que la mitad
transferencia de tecnología, así como herramientas que
99
aplicación
para
la
gestión
de
entidades
y
Actas del II congreso javaHispano
permitan obtener conclusiones estadísticas de los datos
cruzados.
EJBs. Toda esta cantidad de tecnologías está muy bien
Gestión de entidades. Consideramos entidades las
empresas, los centros tecnológicos, grupos de
investigación y organismos. De cada entidad se
•
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.
guarda información sobre su localización, una
Hemos tratado de seguir el estandar a traves de sus
descripción codificada de su actividad, personas de
BluePrints, pero en los escenarios donde JBoss o AXIS
contacto, proyectos en los que participan y derechos
nos proporcionaba una
de propiedad.
eficiente, no hemos dudado en hacer uso de ellas. Estos
Gestión
de
tecnológica.
•
documentos
Aquí
se
de
almacenan
información
y
clasifican
•
consultas
respectivos esquemas XML y se transforman a HTML
búsqueda. Los mecanismos que proporciona J2EE
mediante trasnformadores XLST.
(findBy y select) no son lo suficientemente flexible.
múltiples
criterios
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
Gestión de expedientes de patentes y marcas.
de una provincia determinada no es expresable con
Este apartado está relacionado con las entidades y
una política de roles (ni declarativa ni programada).
almacena la información relativa a las diversas
Diseñamos un evaluador de expresiones (usando
actuaciones que se llevan a cabo con las mismas en
gramáticas JJTree en JavaCC) que son invocados a
relación al patentado o registro de tecnologías.
nivel de Beans por los SecurityProxy de JBoss. Estos
autorizan (o no) al usuario a retirar este dato.
Del análisis de requerimientos de la plataforma a
desarrollar determinamos las siguientes necesidades
principales:
•
SOAP
por
HTTPS.
parametrizando
cifrado de comunicaciones por SSL) y de la base de
datos, nuestra plataforma aporta la posibilidad de
los
Modificando
stubs
WSDL4Java
generados
por
y
esta
herramienta de AXIS, logramos que el protocolo
Seguridad: Además de los servicios de seguridad
XML-RCP SOAP viaje por un canal cifrado.
proporcionados por el sistema operativo (firewall,
•
definir políticas de particionamiento basadas en los
datos (seguridad semántica).
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
Variedad de clientes: Serán consumidores de los
embargo este mecanismo requiere de un redeploy de
servicios de la plataforma clientes web y clientes ricos
la aplicación ante un cambio de estos valores. Para
conectados por Internet con múltiples escenarios de
resolver
velocidad de conexión, proxies, firewalls y routers.
asociadas al tipo de datos que podemos gestionar,
Extensibilidad: Se prevé la incorporación de nueva
funcionalidad al sistema conforme se produzca la
implantación de los servicios existentes.
•
a
construir la sentencia SQL que deseemos a partir de
de envío son el correo electrónico y el fax.
•
atendiendo
JBoss propone una alernativa: DinamycQL. Podemos
Herramienta de distribución de información. El
requieran o que puedan serles de interés. Los medios
•
Consultas dinámicas. El cliente debe poder lanzar
documentos en formato XML validados por sus
documentos tecnológicos a aquellas entidades que lo
•
alternativa más limpia o
casos pueden resumirse en:
objetivo de ésta es la entrega selectiva de aquellos
•
Tecnologías de servidor
La tecnología J2EE abarca desde JDBC hasta JSP y los
Este proyecto consta de cuatro apartados principales:
•
3
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.
100
esta
problemática,
además
de
otras
hemos desarrollado un mecanismo mediante una
MBean que lee los valores de configuración desde un
fichero XML.
Actas del II congreso javaHispano
3.1
Seguridad
Podemos transformar estas acciones a predicados de la
forma expuesta en la Tabla 2. De esta manera un usuario
3.1.1
U puede leer el contenido de un campo F de una entidad
Requerimientos
Un requisito de la aplicación que estamos desarrollando
E si S(U,E) ^ R(U, F).
es la de disponer de un mecanismo que permita
El predicado S, para poder ser evaluado sobre E necesita
controlar las acciones que un usuario puede realizar
de un conjunto de cláusulas o expresiones de restricción
sobre los datos del sistema. Necesitamos restringir el
de U sobre E. Es decir, tenemos que indicar el conjunto
acceso de un usuario a un conjunto de campos de un
de condiciones que una vez evaluadas nos digan si E
bean de entidad y necesitamos limitar el conjunto de
pertenece al dominio de este usuario.
beans de entidad accesibles por ese usuario.
Tabla 2: Predicados
La primera restricción acotará las acciones que se pueden
Acción
realizar en un campo determinado p.ej: el usuario U
Descripción
puede tener acceso de lectura a un campo pero no lo
S(U, E)
Entidad E en dominio
puede modificar. Este tipo de limitaciones casan
R(U, F)
Permiso de lectura de F
perfectamente con el concepto de seguridad descrita en
W(U, F)
Permiso de modificación de F
X(U, F)
Consultar por campo F
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
Repasados los requerimientos de nuestro sistema de
del deploy.
Por contra, limitar el conjunto de beans de entidad sobre
los que un usuario debe tener conocimiento no puede
seguridad vemos que necesitamos de:
1. Una
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
provincia
determinada.
Es
decir,
no
tenemos
capacidad de expresar el dominio de datos
la
expresar
restricciones
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.
usuarios.
5. Un modelo de datos donde alojar metadatos,
que debemos controlar y el receptor de dicha acción.
restricciones y usuarios.
Tabla 1: Acciones básicas de un usuario
Acción
Receptor
Acceso (S)
Entidad
Lectura (R)
Dato miembro
Escritura (W) Dato miembro
Consulta (X)
de
3. Una descripción de los metadatos donde podemos
de los
En la Tabla 1 podemos ver un resumen de las acciones
para
2. Un evaluador de restricciones.
método getEntityList() localizado en un SLSB, esta nos
devuelva solo aquellas entidades que pertenezcan a una
gramática
dominio.
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.
101
Figura 1: Compilación de las restricciones.
Actas del II congreso javaHispano
3.1.2
Restricciones y Gramáticas
valores deben encontrarse en los beans de entidad sobre
Para poder expresar las restricciones de dominio de
los cuales estamos imponiendo restricciones. Estas a su
manera adecuada hemos diseñado una gramática
vez dependen del usuario que realiza la acción.
sencilla que sea fácil de evaluar y de convertir a clausulas
Vemos pues que necesitamos formalizar y almacenar las
WHERE en EJBQL por razones de optimización de las
relaciones y los datos (y metadatos) del modelo de
consultas.
seguridad a través de un modelo de datos. Usaremos
Hemos usado la herramienta JJTree de JavaCC [2] para
diagrama Entidad Relación de la Figura 2 para guiarnos.
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
Figura 2: Diagrama ER de la seguridad.
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
Figura 3: Arquitectura general del sistema.
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
Hay restricciones sobre una entidad y sobre campos de la
reglas de producción en orden inverso a la precedencia
entidad. Necesitamos recopilar en el sistema toda la
de los operadores. Es decir, debemos indicar primero las
información que tengamos sobre los objetos susceptibles
reglas de producción que tienen operadores de más baja
de ser controlados. Hemos denominado a dichos objetos
precedencia.
del sistema, PDO (Persistent Data Object, Objetos de
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
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
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
usando
herramientas
como
XDoclet
[3]
o
bien
introducidos en el sistema de manera manual. Por
desgracia generan una evidente redundancia, puesto
102
Actas del II congreso javaHispano
que los datos securizables son los mismos que tenemos
está en que la seguridad quedaría difuminada y
en los Beans de Entidad (CMP y BMP), que a su vez
repartida en cada uno de los métodos de esta capa. La
tienen una contrapartida en el modelo de datos global
dificultad en el mantenimiento e implementación sería
de la aplicación.
desaconsejable. Si bien tenemos a nuestra disposición
Necesitamos almacenar los datos de los usuarios (login,
nombre, contraseña...) para poder activar el mecanismo
patrones de diseño como los Decorators y los Proxy que
pueden ayudarnos, quizás hay una alternativa mejor.
de autentificación y autorización de J2EE. Cada usuario
Si lográramos poner la seguridad en la capa de
pertenece a un grupo de usuarios y este a su vez dispone
persistencia, donde encontramos lo BMPs y CMPs de
de varios roles dentro del sistema.
nuestro sistema, la seguridad sería óptima. Ningún
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.
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.
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.
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
Las restricciones de dominio asocian el grupo de usuario
a las facilidades en la arquitectura de interceptores que
con el conjunto de restricciones sobre un PDO en
nos brinda este contenedor J2EE de código libre.
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
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
JBoss y los SecurityProxy
nuestro sistema. Hay dos tipos de SecurityProxy, uno que
Llegados a este punto disponemos de un evaluador de
tiene dos métodos (uno que se ejecuta para cada
restricciones y de un sistema que nos devuelve la lista de
llamada a los métodos Home (create, findBy y selects) y
restricciones a evaluar cuando un usuario quiere acceder
otro para los métodos del objeto (postCreate, set, get y
a una entidad. La cuestión ahora es en qué lugar de la
remove)) y otro tiene el mismo interfaz que el CMP o
arquitectura de nuestro sistema sería más conveniente
BMP que estamos interceptando.
realizar estas evaluaciones para aceptar o denegar la
acción.
Este modelo tiene la venta de poder navegar por las
relaciones de manera natural. Podemos establecer una
La Figura 3 es una sobresimplificación de la arquitectura
restricción sobre un elemento relacionado con el que
del sistema. Vemos tres oportunidades donde colocar
entramos tratando. Así puedo decir, por ejemplo, que un
nuestro mecanismo de seguridad.
usuario del sistema no puede acceder a las empresas que
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
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
Si
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
Optimizando el modelo
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
donde recaen las decisiones de negocio. El problema
103
Actas del II congreso javaHispano
consulta del sistema nos traiga el subconjunto de datos
accesibles por el usuario?
4.2
Hylafax
Hylafax es un servidor para el envío y recepción de faxes,
De esta manera limitamos el númer de excepciones
de código libre y amplio uso. Acepta peticiones de
asegurando siempre la corrección del modelo. Aun sin
transmisión vía sockets mediante un protocolo derivado
esta optimización el sistema impide desde su base el
de FTP. Para facilitar la comunicación de nuestra
acceso a los datos no autorizados.
aplicación Java con Hylafax existen librerías también de
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.
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
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
documentos
HTML
documentos
de
(generados
información
a
partir
tecnológica
de
los
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.
mecanismo de integración por Mbeans proporcionado
por JBoss. Los casos en los que ha sido necesaria esta
integración son:
5
Tecnologías de cliente
Inicialmente
consideramos
dos
alternativas
como
framework para la creación de nuestra aplicación de
4.1
Lucene
escritorio. Una era NetBeans Platform, que permite la
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
construcción de aplicaciones Java con componentes
Swing. Descartamos esta solución debido a cuestiones
de rendimiento, consumo de memoria y aspecto general.
la unidad de indexación. En la compilación del índice se
La otra alternativa, y la elegida, era Eclipse. Se basa en el
le añaden documentos y en la búsqueda por palabras se
uso de componentes nativos del sistema operativo
obtienen los documentos que satisfacen las condiciones
cuando estos están disponibles (SWT) y un modelo muy
de las consultas.
sencillo de datos para los componentes JFace.
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.
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
Para el sistema de notificación de modificaciones en los
conjunto mínimo de plugins se reduce a tan solo dos:
documentos indexados se dispone de un acceso a la
org.eclipse.ui y org.eclipse.core runtime, sin embargo
capa de persistencia usando el patrón de diseño Session
podemos usar el resto del API ofrecida por Eclipse.
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.
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
104
Actas del II congreso javaHispano
problemas a la hora de hacer portable el código, aunque
ha permitido ser capaces de ofrecer un tipo de
ha sido solucionado bastante elegantemente. La manera
soluciones al nivel de empresas de
de acceder a los elementos gráficos del sistema
embergadura y con un presupuesto muchísimo mayor.
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
mucha más
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.
esté implementado en Java. El segundo es aportar una
6.2
implementación
Disponer del código fuente de las herramientas usadas
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().
Consideraciones técnicas
ha sido, en determinados casos, decisivo para el éxito de
nuestro
proyecto.
comprendíamos
En
una
ocasiones
en
determinada
que
no
tecnología,
las
la
inmersión en el código fuente nos ha facilitado la
5.3
JFace
información
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.
sigue:
ordenar, filtrar y actualizar los widgets.
Acciones
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
En nuestro desarrollo hemos empleado herramientas que
y
Contribuciones:
rendimiento,
seguridad,
escalabilidad
y
fiabilidad.
Ejemplos son el SGBD PostgreSQL 7.4, el servidor de
incorporan
una
semántica para definir acciones de usuario.
•
encontrábamos
nos permiten asegurar características avanzadas en
Viewers: manejan las pesadas tareas de rellenar,
•
no
de certificados digitales de la SDK de IBM en JBoss).
Las utilidades que suministra están clasificadas como
•
que
aplicaciones J2EE certificado en su versión 4.0 JBoss, el
sistema operativo GNU/Linux o el contenedor de
aplicaciones web Tomcat 5.0.
Imágenes y fuentes: patrones de manejo de
recursos de interfaces de usuario.
•
Diálogos
y
wizards:
6.3
estructuras
para
definir
interacciones complejas con el usuario.
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
6
Conclusiones
principalmente a que los esfuerzos de la comunidad de
desarrolladores se centran en la evolución del propio
6.1
código
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
y
no
información.
en
facilitar
Como
la
ejemplo
transmisión
de
muy
de
esa
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.
105
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-0215ejbsecurity.html
106
Actas del II congreso javaHispano
Integración Continua utilizando herramientas Open
Source
Jesús Pérez Sánchez
www.agile-spain.com / Germinus
jesus.perez@agile-spain.com
los
Abstract
problemas
de
las
metodologías
tradicionales.
Problemas de adaptación a los entornos actuales de
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
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
todo, en llevar este desarrollo del entorno de desarrollo a
novedosas.
producción.
La integración continua es una de las prácticas que
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
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
integración sobre el que realizar pruebas unitarias o de
desarrollo.
aceptación.
La integración continua es también un buen ejemplo de
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
una regla básica de un programador pragmático []:
“Intentar automatizar todo el trabajo repetitivo que
realiza”.
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
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
generación de informes de forma automática.
Palabras clave: Metodologías Ágiles, XP, Integración
Continua, Herramientas Open Source, Agile-Spain,
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
1 Metodologías ágiles
correcto
funcionamiento. Si
Las metodologías ágiles han aparecido dentro del marco
proceso desplegando nuestro software sobre un entorno
correctamente las pruebas
de la Ingeniería del Software como una respuesta ante
107
nuestro
sistema
pasa
podemos completar el
Actas del II congreso javaHispano
donde pueda estar disponible. Este proceso debe poder
las prácticas más complicadas a nivel técnico de aplicar
realizarse muchas veces al día.
de las que nos proponen XP.
El concepto que hay detrás de integración continua
Estos beneficios son los siguientes:
(Continuous Integration o CI) es que se debe integrar el
•
desarrollo de una forma incremental y continua. Esto
Minimiza las sesiones de búsqueda de fallos a la
hora de integrar el código. Fallos realmente
permite encontrar problemas de integración y resolver
complicados de encontrar dado que suelen ser
este tipo de problemas durante el desarrollo.
efectos colaterales de código que ha sido
Integración continua es el término que se utiliza para dar
desarrollado de manera independiente.
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
Permite identificar fallos en el entorno de
producción en etapas tempranas. Esto permite
aplicada en todo tipo de entornos de desarrollo de
ser eficiente en los pasos a producción y evitar
software.
Para
los periodos de integración finales en los
conseguir
automatizar
este
proceso
de
entornos de producción.
construcción, pruebas y despliegue de manera que se
•
realice diariamente muchas veces es necesario también:
•
el cliente, al minimizar el paso de desarrollo a
Almacenar las fuentes en un único lugar del que
un entorno de integración.
pueda obtenerse la última versión del proyecto
•
(y versiones anteriores).
•
Eficiencia del equipo de desarrollo: no es
necesario todo el conjunto de pruebas en el
Automatizar el proceso de construcción de
entorno local, minimiza el tiempo de paso a
manera que se pueda, con un único comando,
producción.
construir todo el sistema a partir de las fuentes
•
Minimización del tiempo de realimentación con
•
Aumenta la confianza en el cdigo subido al
Automatizar las pruebas de forma que sea
control de versiones.
posible y de forma automática, saber si todo
está bien o hay algún problema.
4
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
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
necesario realizarlo en la actualidad gracias a la aparición
Open-Source.
de plataformas abiertas de integración continua.
El movimiento de Open-Source se ha consolidado en la
actualidad como un punto de referencia para cualquier
3
Beneficios de la Integración Continua
desarrollo. El extenso conjunto de herramientas, la
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
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
108
Actas del II congreso javaHispano
libres cuyo coste de desarrollo es cero. Unas soluciones
nuestro software que hayamos generado hace tiempo
cuya funcionalidad esta en continua evolución y que nos
siempre para construir el software únicamente nos
permitirán evolucionar tecnológicamente con ellas.
hayamos apoyado en las fuentes que existían el control
Para Integración continua podemos encontrar diferentes
soluciones tanto Comerciales como Open-Source:
•
CruiseControl (Open-Source)
•
AntHill(Comercial/Open-Source)
•
DamageControl
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.
El más extendido de estos frameworks de integración es
Será importante ser cuidadoso con el código que
Cruise-Control que ha sido desarrollado por una de las
introducimos en el control de versiones para evitar que
empresas más importantes dentro del movimiento ágil,
nuestros compañeros al actualizarse tengan problemas
ThoughtWorks, por lo que supone probablemente la
para seguir desarrollando.
mejor forma de introducirse en esta práctica.
La experiencia al final nos hace ver que lo necesitaremos
incluso cuando realicemos desarrollos individuales y en
4.1 CruiseControl
los que tengamos una única entrega, dado que es fácil
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
continua la primera condición es tener un repositorio
con todas las fuentes del proyecto. Existen diferentes
control
de
versiones
hicieron en las fuentes desde una fecha determinada,
evita la proliferación de copias de seguridad de nuestro
etc…).
Para poder implantar una herramienta de integración
de
desarrollar (permite poder identificar los cambios que se
código, identifica claramente cuál es la ultima versión,
4.1.1 Control de Versiones
repositorios
descubrir que es una herramienta muy potente para
como
CVS,
4.1.2 Pruebas Automatizadas
El siguiente paso para poder llegar a implantar
Integración Continua es el desarrollo de pruebas
Subversión, ClearCase, VisualSourceSafe, etc. Cada uno
automatizadas.
de estos repositorios tiene características diferentes que
Implantar esta práctica es uno de los retos más difíciles
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
que nos encontraremos en la implantación de la
integración continua.
Desarrollar un conjunto de pruebas completas de
nuestro
sistema
dependerá
del
es
una
entorno
tarea
de
cuya
ejecución
complejidad
de
nuestra
ramas de trabajo mucho mas potentes.
aplicación y de las interacciones con sistemas externos.
Utilizar Control de Versiones es una práctica se hace
implicaría tener diferentes conjuntos de pruebas:
especialmente imprescindible cuando se trabaja en
Un conjunto de pruebas completas de nuestro sistema
entornos colaborativos y en los que se desarrolla de una
•
Pruebas Unitarias
forma evolutiva para que el software pueda estar
•
Pruebas de Rendimiento
razones han hecho de estos sistemas el corazón de los
•
Pruebas de Integración con sistemas externos
proyecto de Software Libre.
•
Pruebas de Diseño (Accesibilidad)
El control de versiones contiene toda la historia de los
•
Pruebas Funcionales
disponible desde las primeras versiones. Estas dos
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
En el modelo tradicional de desarrollo este tipo de
pruebas se realizaban una vez finalizado el desarrollo. No
109
Actas del II congreso javaHispano
•
obstante este enfoque no suele funcionar en la mayoría
de los proyectos de desarrollo y es realmente poco
unitarias sobre actions de struts
efectivo.
•
Desarrollar pruebas automáticas nos permite comprobar
nuestro
sistema
cumple
con
la
DBUnit: Suite para pruebas muy dependientes
de los datos almacenados en Bases de Datos
en cualquier momento y ejecutando la ‘suite’ de pruebas
si
StrutsTestCase: Extensión para hacer pruebas
•
funcionalidad
HttpUnit,
JUnit,
CanooWebTest:
Pruebas
directamente contra la aplicación web
implementada hasta el momento. Esta facilidad es
tremendamente útil durante el desarrollo, puesto que
Realizar pruebas puede ser complicado pero siempre es
nos permitirá desarrollar cambios con seguridad, sin
posible. Incluso en entornos muy específicos en los que
tener que pagar el esfuerzo de volver a probar todo.
no encontremos suites que simulen el comportamiento
Dejar las pruebas para el final del desarrollo nos privará
de los elementos externos, es posible desarrollarnos
de esta ventaja.
mediante
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
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.
se acompaña de un conjunto de utilidades que permitirá
4.1.3 Automatización (Scripting)
presentar los resultados en diferentes formatos (XML,
Una vez llegados a este punto nos encontramos en
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.
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.
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
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
funcionamiento correcto de todas las funcionalidades.
de nuestro desarrollo hay otra razón que muchas veces
Sobre JUnit se han desarrollado muchas extensiones
importante: la capacidad de poder repetir los procesos
realmente útiles que ofrecen librerías para facilitar cierto
tipo de pruebas. Especialmente interesante son las
librerias de:
•
durante el desarrollo es muy sencillo y muy
valioso, especialmente en aquellas clases criticas
como las de acceso a Basede Datos, las que
operaciones
pesadas
(algoritmos,
parseo de XML, integración con otros sistemas
externos, etc..)
•
Cactus:
es en mi opinión mucho más
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
JUnitPerf: Introducir pruebas de rendimiento
realicen
queda oculta y que
Para
(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
permitir
pruebas
realizadas
directamente sobre el contenedor. Pruebas
replicar o repetir cualquier proceso previo que hubiera
sido exitoso.
unitarias sobre el entorno final
110
Actas del II congreso javaHispano
Pero automatizar un proceso puede ser una tarea que
entorno real a escala reducida. Dependiendo de los
conlleve mucho esfuerzo. Entonces la pregunta es ¿Qué
sistemas involucrados con el software que se desarrolla
debemos automatizar?. En nuestra opinión cualquier
en algunos casos se compartirá alguno de estos sistemas
proceso manual que vayamos a realizar en más de una
en lugar de instalarlos en el entorno local. También es
ocasión.
posible solucionar este problema utilizando clases que
Para automatizar todos estos procesos Java cuenta con
una herramienta ANT que nos permite llevar a cabo la
en lugar de utilizar los servicios remotos, simulen este
comportamiento.
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
Cada desarrollador subirá periódicamente sus nuevos
ofrece una posible implementación de todas estas tareas
desarrollos al entorno de control de versiones e irá
de alto nivel. (preguntar a Dani)
actualizándose
con
las
modificaciones
que
vayan
realizando otros miembros del equipo.
4.1.3 Configuración de CruiseControl
El entorno de integración continua (en nuestro caso
Hay diferentes formas de abordar un proyecto de
CruiseControl) suele estar instalado en el entorno de
desarrollo. Nos encontramos desde proyectos en los que
todo el equipo desarrolla en misma máquina, hasta
integración. Esto permite que podamos desplegar de
una manera sencilla el software sobre el entorno de
proyectos en los que cada desarrollador tiene asignado
integración una vez que ha pasado las pruebas.
su ordenador personal y una máquina adicional similar al
Para instalar CruiseControl es necesario tener en cuenta
entorno
de
desarrollo.
También
nos
encontramos
empresas que tiene un servicio de control de versiones
los siguientes directorios
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
En estos directorios se instalar
producción.
•
CruiseControl: En este directorio instalaremos la
herramienta de integración continua.
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
111
•
Tomcat: Tenemos la opción de publicar los
resultados mediante una aplicación web. Esto
Actas del II congreso javaHispano
•
nos obligará a instalar un contenedor de
La Integración continua es una práctica de la que todo el
servlets como Tomcat
mundo ha oído hablar pero que muy pocos equipos de
Fuentes
del
Proyecto:
Este
directorio
lo
utilizaremos para que CruiseControl tenga su
copia del código del control de versiones.
desarrollo aplican (incluyendo aquellos que utilizan
metodologías ágiles como XP)
¿A que se debe que no este nada extendida?.
CruiseControl no tiene una arquitectura muy sofisticada,
comprobará una serie de condiciones para lanzar una
5.1 Problemas implantando Integración
Continua
serie de acciones.
El
La otra parte de la arquitectura es la herramienta de
aplicarla es que en la mayoría de los casos supone la
consta
de
un
proceso
que
cada
cierto
tiempo
publicación de la actividad de este proceso. Esta
herramienta
esta
desarrollada
en
Java
y
principal problema que nos hemos encontrado al
introducción de otras prácticas en las que se apoya.
esta
•
Control de Versiones: Necesitamos tener control
empaquetada en un war. Instalando un Tomcat y
de versiones de nuestro código, de manera que
desplegando esta aplicación configurada correctamente
podamos
tendremos disponibles via web la información de la
proyecto. Esta es una practica muy extendida y
actividad del proceso principal de CruiseControl
no suele suponer un problema.
Toda la configuración de CruiseControl esta centralizada
•
recuperar
cualquier
versión
del
Pruebas Automáticas: La integración continua
en un único fichero. En este fichero podremos configurar
pierde gran parte de su valor si no existen.
todas las propiedades del proceso de integración
Implantar esta práctica una vez comenzado el
continua. Las más importantes son:
proyecto es muy costoso y supone una parada
•
del desarrollo. Incluir pruebas automatizadas al
ModificationSet: En este propiedad se especifica
proyecto y programar desarrollando pruebas es
a CruiseControl cuales son las condiciones que
uno de los cambios de filosofía necesario si
se tiene que producir para lanzar un proceso de
construcción,
Software.
•
despliegue
Generalmente
y
lo
pruebas
queremos implantar Integración Continua
del
asociaremos
a
•
Construcción y despliegue automatizados: Esta
cambios en nuestro control de Versiones
es una de las tareas que tendremos que realizar
Schedule: En esta propiedad especificaremos
si no existen los scripts que permitan llevar a
cabo este proceso sin intervención manual.
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
al equipo de desarrollo.
más disciplinado. En muchos proyectos no se es
consciente de que se trabaja en equipo hasta que llega el
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
Experiencia Real
desarrollos añadirán nuevas funcionalidades evitando
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 impone un desarrollo en equipo
momento de la integración final.
como notificaremos de los resultados de prueba
5
5.2 Buenas Prácticas
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.
112
Actas del II congreso javaHispano
Para
que
este
desarrollo
incremental
funcione
•
Coordinar
aquellos
cambios
o
correctamente la experiencia nos dice que es necesario
reestructuraciones que influyan en gran parte
seguir las siguientes prácticas:
del código: La integración continua implica un
•
elevado
Desarrollar pruebas a medida que se desarrollan
veces es más eficiente hacer este tipo de
modifique alguna funcionalidad también será
cambios
necesario modificar su conjunto de pruebas.
desde
situaciones
estables,
para
intentar evitar efectos colaterales. Es posible
Utilizar desarrollo dirigido por pruebas TDD
que estos cambios sean realizados por cada
facilita esta tarea.
programador en los módulos en los que esta
Política de Semáforos: Una vez que utilicemos
integración continua el sistema nos informara
del estado del software De esta manera
continuamente
trabajando.
•
del
entorno
Nuestra
Integración
de
experiencia
Continua
es
que
integración
aplicando
es
muy
conveniente tener un responsable encargado de
repositorio de versiones no pase las pruebas. En
que este entorno funcione correctamente y de
ese caso tendremos el semáforo en rojo para
que
subir nuevo código al CVS. Esto nos permitirá
el
equipo
esta
siguiendo
las
reglas
anteriores. Esta persona será la responsable de
no introducir nuevas clases antes de identificar
arreglar aquellos errores que surgen sin que se
cuales han sido las clases responsables de este
haya realizado ningún cambio por el entorno en
problema. Si el control de versiones nos ha
el que se ejecutan los test.
enviado un mail avisándonos del éxito de
nuestras pruebas, entonces en ese momento el
Responsable
continua:
notificaciones
cuando el código que tengamos en nuestro
•
Los mails que genera el Control de Versiones no
semáforo estar verde para subir nuevo código
son Spam: Nuestra experiencia nos dice que hay
estará en Verde.
ciertos periodos en los que se produce cierta
inestabilidad en el entorno de control de
Tiempo máximo de solución de errores en el
versiones.
control de Versiones: En la medida de lo posible
En esos momentos es cuando al
recibir muchos emails de sistema de integración
tenemos que minimizar el tiempo en que el
continua nos sentimos tentado de tratar este
desarrollo que hay en el control de versiones no
como Spam (redirigiendolo a la carpeta de
pasa las pruebas. En aquellos casos en los que
borrar o a otra carpeta que no consultaremos).
sea difícil arreglar un problema que hemos
Estas
detectado una vez subido el código al control
situaciones
tenemos
que
tratar
de
evitarlas tratando de solucionar el problema de
de versiones la mejor opción es volver al código
la
de la versión anterior.
•
Estas
a muchos módulos. En estos casos muchas
tener su conjunto de pruebas. Cuando se
•
coordinación.
en aquellas modificaciones que vayan a afectar
se integre en el control de Versiones deberá
recibiremos
de
coordinaciones son especialmente importantes
funcionalidades: Cada nueva funcionalidad que
•
grado
inestabilidad
lo
antes
posible
e
interrumpiendo temporalmente el envió de
Minimizar el tiempo entre integraciones: Uno
correos.
de los objetivos principales de la integración
integración
continua
atenderlo lo antes posible para conseguir todos
es
realizar
continuamente
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.
correos
continua
nuestro
sistema
de
debemos
tratar
de
lo beneficios de implantar esta práctica.
integraciones, cuanto mas a menudo se realicen
mejor funcionara el proceso. Por este motivo
Los
•
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
113
Actas del II congreso javaHispano
2004http://www.javaranch.com/journal/200409/DrivingOn
CruiseControl_Part1.htm
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
[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
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/conti
nuous Integration.html
[3]
Lasse Koskela. . Driving on CruiseControl., JavaRach
Journal,
September
114
Descargar