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