TRABAJO FIN DE ESTUDIOS PROYECTO FIN DE CARRERA Instalador configurable a través de ficheros XML Miguel Marañón Grandes Tutor: Julio Rubio García Curso 2009-2010 Instalador configurable a través de ficheros XML, trabajo fin de estudios de Miguel Marañón Grandes, dirigido por Julio Rubio García (publicado por la Universidad de La Rioja), se difunde bajo una Licencia Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported. Permisos que vayan más allá de lo cubierto por esta licencia pueden solicitarse a los titulares del copyright. © © El autor Universidad de La Rioja, Servicio de Publicaciones, 2012 publicaciones.unirioja.es E-mail: [email protected] UNIVERSIDAD DE LA RIOJA Facultad de Ciencias, Estudios Agroalimentarios e Informática PROYECTO FIN DE CARRERA Ingeniería Técnica en Informática de Gestión Un instalador configurable a través de ficheros XML Alumno: Miguel Marañón Grandes Director: Julio Jesús Rubio García Logroño, julio de 2010 1. Resumen La instalación de programas computacionales (software) es el proceso por el cual nuevos programas son transferidos a un computador y, eventualmente, configurados, para ser usados con el fin para el cual fueron desarrollados. Un instalador es un programa que realiza el proceso de instalación de un determinado software. Pues bien, en este proyecto se explicará cómo construir un creador de instaladores; es decir, una aplicación que permita elaborar instaladores de todo tipo, configurables mediante los datos almacenados en un fichero XML. Además, la aplicación que desarrollaremos deberá ser capaz de permitir al usuario que ejecutará en última instancia la instalación cambiar algunos parámetros del instalador, así como proporcionar un desinstalador que revierta las modificaciones producidas por el instalador. Es necesario remarcar que la metodología empleada a la hora de desarrollar la aplicación se alejó ligeramente de algunos de los procedimientos habituales en Ingeniería del Software. Para dar un carácter más experimental al proyecto, se consideró conveniente no determinar completamente desde el comienzo los requisitos que debía cumplir el creador de instaladores. De este modo, ha sido necesario ir modificando los requisitos poco a poco, a medida que implementábamos nuevas funcionalidades. 2 2. Índice 2.1. Índice de contenidos 1. 2. Resumen......................................................................................................... 2 Índice.............................................................................................................. 3 2.1. Índice de contenidos ......................................................................................... 3 2.2. Índice de figuras y tablas .................................................................................. 5 3. Introducción.................................................................................................... 6 4. Memoria......................................................................................................... 8 4.1. Documento de Objetivos del Proyecto (D. O. P.) .............................................. 8 4.1.1. Definición del proyecto ................................................................................ 8 Antecedentes.......................................................................................................... 8 Objetivos del proyecto ........................................................................................... 9 Descripción del producto ....................................................................................... 9 4.1.2. Alcance del proyecto .................................................................................. 10 Informe del alcance .............................................................................................. 10 Entregables ........................................................................................................... 10 Actividades de apoyo............................................................................................ 11 4.1.3. Recursos humanos, personal y plan de comunicaciones ........................... 11 Conexiones del proyecto ...................................................................................... 11 Plan de dirección del personal ............................................................................. 11 Plan de comunicaciones ....................................................................................... 12 4.1.4. Dirección de riesgos.................................................................................... 12 Fuentes de riesgo.................................................................................................. 12 Síntomas de riesgo ............................................................................................... 13 Cuantificación de los riesgos ................................................................................ 13 Plan de contingencia............................................................................................. 14 4.1.5. Planificación del proyecto .......................................................................... 14 Estructura de Descomposición del Proyecto (EDP).............................................. 15 Listado de actividades .......................................................................................... 16 Calendario de trabajo ........................................................................................... 18 Diagrama de Gantt ............................................................................................... 19 4.2. Análisis ............................................................................................................ 21 4.2.1. Análisis de requisitos .................................................................................. 21 4.2.2. Casos de uso ............................................................................................... 23 Definir nombre instalador .................................................................................... 23 Definir archivos a copiar....................................................................................... 24 Definir accesos directos........................................................................................ 25 Definir paquetes ................................................................................................... 26 Definir accesos directos menú Inicio y escritorio................................................. 27 Definir usuarios finales ......................................................................................... 28 Definir iconos........................................................................................................ 29 Definir ruta instalación ......................................................................................... 30 Definir grupo programas ...................................................................................... 31 3 Definir modificación registro................................................................................ 32 Definir archivos auto-ejecutables......................................................................... 33 Ejecutar instalador................................................................................................ 34 4.2.3. Diagrama de casos de uso .......................................................................... 35 4.3. Diseño ............................................................................................................. 36 4.3.1. Descripción de la clase Creador_instaladores............................................ 37 4.3.2. Descripción de la clase Construct............................................................... 38 4.3.3. Descripción del archivo Make.bat .............................................................. 45 4.3.4. Relaciones entre los archivos de la aplicación ........................................... 46 4.3.5. Interfaz del usuario creador ....................................................................... 46 Descripción ........................................................................................................... 46 Precondiciones ..................................................................................................... 48 Poscondiciones ..................................................................................................... 48 4.3.6. Interfaz del usuario final............................................................................. 49 Captura de pantalla .............................................................................................. 49 Descripción ........................................................................................................... 49 Precondiciones ..................................................................................................... 51 Poscondiciones ..................................................................................................... 51 Diagrama de estados ............................................................................................ 52 4.3.7. Interfaz para el desinstalador..................................................................... 53 4.4. Implementación .............................................................................................. 54 4.5. Pruebas ........................................................................................................... 60 4.5.1. Pruebas de comprobación de la funcionalidad .......................................... 60 4.5.2. Pruebas de la interfaz de usuario ............................................................... 64 4.6. Gestión del proyecto....................................................................................... 66 4.7. Conclusiones ................................................................................................... 68 4.7.1. Concordancia entre resultados y objetivos................................................ 68 4.7.2. Lecciones aprendidas ................................................................................. 68 4.7.3. Líneas de ampliación posibles .................................................................... 69 4.8. Bibliografía ..................................................................................................... 70 4.9. Anexos............................................................................................................. 71 4.9.1. ANEXO I: Manual de instrucciones del usuario creador............................. 71 4.9.2. ANEXO II: Cronología del Proyecto Fin de Carrera ..................................... 74 4.9.3. ANEXO III: Actas de reuniones.................................................................... 79 4 2.2. Índice de figuras y tablas Figura 1: Esquema global de la aplicación........................................................................ 9 Figura 2: Modelo de planificación .................................................................................. 15 Figura 3: Diagrama EDP .................................................................................................. 16 Figura 4: Calendario de trabajo ...................................................................................... 19 Figura 5: Diagrama de Gantt del trabajo planificado ..................................................... 20 Figura 6: Diagrama de casos de uso ............................................................................... 35 Tabla 1: Elementos y atributos para modificar el registro ............................................. 40 Tabla 2: Claves del fichero de configuración y su descripción ....................................... 45 Figura 7: Diagrama de colaboración entre los ficheros de la aplicación........................ 46 Figura 8: XML-Schema del fichero Instalador.xml.......................................................... 47 Figura 9: XML-Schema del elemento lugaresInstalacion ............................................... 47 Figura 10: Prototipo de la interfaz del usuario final....................................................... 49 Figura 11: Prototipo de interfaz para cancelar la instalación ........................................ 50 Figura 12: Prototipo de interfaz para confirmar la instalación ...................................... 51 Figura 13: Diagrama de estados de la interfaz del usuario final .................................... 52 Figura 14: Prototipo de interfaz para ejecutar el desinstalador .................................... 53 Figura 15: Prototipo de interfaz para confirmar la desinstalación................................. 53 5 3. Introducción El proyecto que queremos desarrollar consiste en la construcción de un creador de instaladores configurable a través de un fichero XML, de modo que parte de la configuración inicial dada por este fichero pueda ser modificada posteriormente por el usuario que a la postre instalará la aplicación para la que se construyó el instalador. Las funciones del creador de instaladores no se limitarán a proporcionar el instalador del programa que queremos que se instale, sino también a crear los archivos y procesos necesarios para desinstalarlo del equipo (es decir, un desinstalador de ese mismo programa). Además, deberá dar la opción de que el instalador creado permita configurar la instalación en los aspectos más usuales: creación de accesos directos, elección del directorio de instalación, etcétera. Para la construcción de este creador de instaladores nos fijaremos en las características de algunos productos de software similares ya existentes. Si bien uno de los objetivos del proyecto será emularlos en lo más básico, se intentará mejorarlos en la medida de lo posible. Las razones por las que he elegido este tema para realizar el Proyecto Fin de Carrera son tres: por un lado, la posibilidad de colaborar con el Departamento de Matemáticas y Computación; por otro, la opción de formar parte del equipo de desarrollo de la aplicación para alumnos de matemáticas de secundaria TutorMates (este aspecto lo explicaremos con más detalle en el siguiente párrafo); y finalmente, mi deseo de embarcarme en un proyecto eminentemente tecnológico y de investigación que me proporcione una formación de garantías para el desarrollo de la profesión de ingeniero informático. Centrándonos en TutorMates, AddLink Research, S.L. es la empresa encargada del desarrollo y comercialización de esta aplicación, dirigida a los alumnos y profesores que forman parte de la enseñanza de las matemáticas en secundaria. Al igual que la mayoría de las aplicaciones informáticas, TutorMates necesitaba un instalador de modo que fuera más fácil incorporar el programa al equipo del usuario que lo utilizara. Así, el equipo de desarrollo de TutorMates decidió incluir en el proyecto un creador de instaladores desarrollado en Java y de código abierto para cubrir sus necesidades iniciales y poder contar con él desde el primer día. Es posible que la herramienta que vamos a construir se encargue de la elaboración de este instalador. 6 Existen determinadas funcionalidades del creador de instaladores que finalmente no se considerarán en el proyecto, como es la incorporación de un soporte multilingüe (hay que tener en cuenta que TutorMates es una herramienta pensada para ser usada en todo el territorio nacional, por lo que debería estar traducida, al menos, al gallego, vasco y catalán), una interfaz para el usuario creador de la instalación o un soporte multiplataforma, de modo que no sólo funcione en Windows. La razón por la que no se considerarán tales requisitos es la falta de tiempo: la fecha tope de entrega de la memoria se ha establecido en julio de 2010, siendo la fecha de inicio octubre de 2009. 7 4. Memoria En este apartado desarrollaremos el cuerpo de la memoria, uno de los entregables más importantes del proyecto. 4.1. Documento de Objetivos del Proyecto (D. O. P.) En este capítulo se especificarán asuntos relativos al proyecto tales como sus objetivos, descripción, entregables principales, plan de trabajo y otros aspectos. 4.1.1. Definición del proyecto En este punto se explicarán, entre otras cosas, los antecedentes en los que viene enmarcado el proyecto, los objetivos que se pretenden y una descripción del producto que se desea elaborar con él. Antecedentes El proyecto se enmarca dentro de la construcción de una aplicación que servirá como herramienta de apoyo a los estudiantes de matemáticas de secundaria: TutorMates. En concreto, lo que se pretende con dicho proyecto es la construcción de un creador de instaladores que pueda ser aprovechado por la empresa que desarrolla este producto con el fin de no utilizar programas de instalación externos a ella y, de este modo, fabricar el instalador definitivo de la aplicación. Este proyecto se realiza para la empresa Addlink Research, S.L., propietaria de la marca TutorMates, en colaboración con el Ministerio de Educación, Geogebra y las universidades de Cantabria y La Rioja. El profesor de la UR Julio Rubio García actuó como tutor académico del proyecto, mientras que el papel de director del proyecto (y, por tanto, responsable de todas las decisiones tomadas en él) recayó en mi persona. Se trata de un proyecto clave dentro de este marco, porque de él depende que la elaboración del instalador de la aplicación utilice herramientas ajenas a la empresa. Por otro lado, el producto que se espera obtener debería emular (y si fuera posible, mejorar) a alguno de los creadores de instaladores ya existentes (en concreto, a IzPack, basado precisamente en la configuración de la instalación a través de ficheros XML). Este hecho permitiría la opción de realizar (si la empresa lo creyera conveniente) el instalador definitivo de TutorMates bajo mi responsabilidad, como algo fuera de proyecto pero con una cierta remuneración económica. 8 4.1.2. Alcance del proyecto En este apartado se detallará qué se hará y qué no se hará en el proyecto, así como los entregables que se depositarán. Informe del alcance Este proyecto está englobado en otro más grande, basado en la realización de una aplicación que sirva como herramienta de aprendizaje matemático a los alumnos y profesores de la educación secundaria: TutorMates. Esta aplicación deberá cumplir los siguientes requisitos: El desarrollo multiplataforma: Windows, Linux y Mac OS X. El motor de cálculo reposará en herramientas de uso libre y gratuito, como MAXIMA y Geogebra. La interfaz de usuario desarrollada en Java tendrá como principales referentes la facilidad de uso y la interacción con el usuario final (el alumno). El soporte multilingüe. El creador de instaladores no cumplirá, en un principio, todas estas características. Concretamente, sólo será válido para Windows, ya que se usarán mandatos propios y exclusivos de este sistema operativo, y por falta de tiempo no dispondrá del soporte multilingüe. Sin embargo, sí que se esperará que cumpla los requisitos relativos a la facilidad de uso de su interfaz. Por otro lado, como hemos explicado más arriba, la aplicación deberá imitar (o mejorar, en la medida de lo posible) a las herramientas de construcción de instaladores más conocidas hoy en día. En concreto, estará inspirada por IzPack, de modo que ambas estén desarrolladas en lenguaje Java y recojan las opciones que puedan estar disponibles en las instalaciones mediante la lectura de ficheros XML. Un aspecto que nuestra aplicación mejorará con respecto a IzPack es dar la opción al usuario que instalará el programa de instalar en su equipo la máquina virtual de Java, necesaria para el correcto funcionamiento del creador de instaladores, en caso de no disponer de ella. Entregables Una vez que el proyecto esté terminado y listo para entregar, tendrán que estar finalizados los siguientes entregables: Ficheros en Java de la aplicación (creador de instaladores), junto con un script que ponga en ejecución los archivos compilados, las instrucciones de uso en un fichero en formato de texto y el resto de archivos necesarios para su correcta ejecución. Todo esto será entregado, precisamente, en forma de un instalador creado por la misma aplicación. Memoria del proyecto. Presentación del proyecto preparada. 10 Actividades de apoyo Será valiosa una buena documentación sobre: XML. Java y C++. JDom. Swing/AWT (para la interfaz gráfica del instalador). 4.1.3. Recursos humanos, personal y plan de comunicaciones En este punto se explicará qué roles desempeñan las personas que participan en el proyecto, así como las obligaciones que deben cumplir y las decisiones que deben tomar. Conexiones del proyecto Estas son las personas que participarán en el proyecto, de forma directa o indirecta: Miguel Marañón: Director y desarrollador del proyecto. o Decisiones a tomar: todas. o Dedicación: completa. Julio Rubio: Tutor de la Facultad. o Decisiones a tomar: cualquiera, en caso de que lo estime oportuno. o Dedicación: esporádica (solo en caso de que su intervención en el Proyecto Fin de Carrera –de aquí en adelante, PFC –sea necesaria). Jónathan Heras Vicente: Miembro del Departamento de Matemáticas y Computación de la Universidad de La Rioja. o Decisiones a tomar: ninguna que afecte al desarrollo del proyecto, pues colaborará desinteresadamente como consejero y supuesto “cliente” de mi aplicación. o Dedicación: esporádica, siempre que él quiera. Miembros del tribunal evaluador: Grupo de profesores que evaluarán el PFC. o Decisiones a tomar: la nota final del proyecto. o Dedicación: solamente lo necesario para evaluar el proyecto y acudir a la defensa del PFC. Plan de dirección del personal Yo soy el director del proyecto; por consiguiente, las decisiones finales serán tomadas por mí, sea cual sea su naturaleza. No obstante, Julio Rubio aconsejará cuando él lo considere oportuno o cuando yo lo solicite. 11 Plan de comunicaciones Las herramientas que se emplearán para la comunicación dentro del PFC son: Reuniones: Servirán de comunicación entre Julio Rubio (tutor académico) y yo. En ellas se tomarán las decisiones relativas al proyecto y se tratarán los aspectos más trascendentes. Correo electrónico. Defensa: Se utilizará una presentación de 30 minutos de duración máxima para comunicar al Tribunal evaluador los aspectos más relevantes del proyecto. En ella se utilizarán medios como transparencias y una demostración “en vivo” de las características de la aplicación. 4.1.4. Dirección de riesgos En este apartado se identificarán las fuentes principales de riesgo y se creará un plan a seguir. Fuentes de riesgo A continuación se enumerarán las fuentes de riesgo identificadas para este proyecto. 1. La poca experiencia en el desarrollo de proyectos es una fuente de riesgo potencial. Hasta este momento, el alumno sólo tiene experiencia en realizar trabajos de índole informática a menor escala, no habiendo ninguno que alcance la magnitud de este proyecto. Con mucha seguridad, esta inexperiencia ocasionará diversos fallos en todos los aspectos relativos al proyecto: planificación, diseño, análisis… 2. La estimación de las fechas para las actividades que conforman el proyecto puede no ser la adecuada, ya que el alumno no podrá tener dedicación exclusiva al mismo hasta mediados del mes de junio de 2010. Esto hará que el alumno sólo pueda trabajar una media de 15 horas semanales, las cuales pueden llegar a ser insuficientes, provocando el consiguiente retraso en las tareas programadas. 3. El diseño realizado por el alumno puede no ser óptimo. Puede haber algunos cambios en el diseño que ocasionen rehacer necesariamente el trabajo. 4. Puede haber problemas software ocasionados por la incorrecta manipulación de las herramientas disponibles. Dicho riesgo se centra sobre todo en la utilización de las variables de entorno del sistema PATH y CLASSPATH. El uso indebido de estas variables puede ocasionar la incorrecta ejecución de algunos comandos, tanto de Java como del sistema operativo Windows. 5. Al disponer el alumno de un periodo relativamente pequeño de tiempo (que no llega a los 9 meses), hay riesgo de que el alumno caiga enfermo o sufra algún percance que le impida trabajar en el proyecto dentro de los plazos estimados. 12 Síntomas de riesgo Al detectar alguno de estos síntomas se activará inmediatamente el plan de contingencia. 1. Continuos errores que impiden avanzar en el desarrollo del proyecto en las fechas planificadas. 2. A medida que el proyecto avanza, puede haber un continuo retraso en la finalización de paquetes de trabajo que nos haga pensar que tal vez la estimación de las fechas que se había realizado no era la correcta. 3. En tiempo de diseño se realizará una exhaustiva revisión del mismo. Es entonces cuando se decidirá si remodelar el diseño o dejarlo como está. 4. Es sencillo percatarse del incorrecto funcionamiento de las herramientas utilizadas, pues esto impide por completo la ejecución de la aplicación. 5. Síntomas de enfermedad, aparte de los propios síntomas médicos, pueden ser el descenso de la productividad y el uso continuo de trabajo excesivo sin poder llegar a tiempo a las fechas planificadas. Cuantificación de los riesgos Cada fuente de riesgo tendrá una diferente evaluación: desde una fuente de riesgo potencial cuyo daño se considerará elevado hasta una fuente de riesgo cuyo daño se considerará mínimo. 1. El rumbo del proyecto, debido a los continuos informes semanales del alumno, va a estar siempre bajo la supervisión de Julio Rubio, por lo que el riesgo en este aspecto es pequeño: si Julio Rubio detectara alguna anomalía lo suficientemente grave como para poner en compromiso toda la estimación realizada, informará de inmediato con el fin de que el alumno pueda corregir a tiempo. 2. La estimación de fechas realizada para las actividades que conforman el proyecto puede no ser la apropiada. Hay que recordar que el alumno no puede trabajar a tiempo completo en el proyecto hasta el mes de junio de 2010, de modo que las horas que dedique al proyecto durante el curso académico pueden no ser suficientes. 3. Un cambio en el diseño a destiempo es un riesgo bastante grave, ya que puede suponer que el trabajo de varios meses caiga en saco roto. 4. Podemos suponer que el riesgo relacionado con el uso indebido de las variables de entorno es de tipo medio-alto, ya que podría suponer la imposibilidad de poder ejecutar en la máquina afectada el proyecto hasta no descubrir el origen real del error. 5. Ya que la incapacidad física del alumno puede ser prolongada o no, este punto será considerado de riesgo medio en el proyecto. 13 Plan de contingencia Para cada fuente de riesgo identificada se actuará según lo descrito en este punto. 1. Se pedirá una reunión con Julio Rubio con el fin de que pueda reorientar al alumno según crea conveniente. 2. Se realizará un cambio en la estimación de las fechas en el plan del proyecto, intentando que las nuevas sean más acordes a la realidad que se está observando. Los motivos por los cuales se habrá realizado el cambio serán tomados en cuenta en un futuro, con el fin de evitar caer en los mismos errores. 3. Si se detectara que el diseño es incorrecto, el alumno realizará los cambios que estime oportunos antes de comenzar la implementación. 4. Si se detectaran problemas con las herramientas de software, el alumno deberá tratar de resolverlos en primera instancia, siendo consciente de las posibles fuentes de origen del error. Si después de un tiempo considerable el alumno no hubiera conseguido solventar sus problemas y además éstos le supusieran un grave impedimento para seguir con la realización del proyecto, será al fin Julio Rubio el que tomará cartas en el asunto. 5. La principal medida de contingencia frente al agotamiento consistirá en ir reduciendo paulatinamente todas las funciones que no se consideren críticas para el sistema. 4.1.5. Planificación del proyecto En primer lugar, es necesario indicar que la evolución de este proyecto se basará en la sucesiva repetición de dos actividades mientras se esté elaborando, a saber: 1. Estudio de una de las funcionalidades del creador de instaladores IzPack. 2. Desarrollo de una nueva versión del generador de instaladores que incluya esta nueva funcionalidad, de modo que se realicen para dicha versión las pertinentes fases de análisis, diseño e implementación. Por tanto, el método de trabajo que seguiré consistirá en la elaboración de prototipos un poco más completos en cada iteración, los cuales incluirán o mejorarán alguna de las características que proporciona IzPack. Este método de trabajo es muy similar al conocido como AGILE Extreme Programming, que se basa más en la adaptabilidad que en la previsibilidad y que busca acercarse al producto final a través de sucesivas aproximaciones y continuos cambios en los requisitos. La razón por la que se eligió este modo de trabajo es el desconocimiento a priori de las funcionalidades del IzPack, pues no olvidemos que el objetivo final es la elaboración de un creador de instaladores que emule o mejore a ese programa. Estas funcionalidades se irán descubriendo a lo largo del desarrollo del proyecto, de modo que cada pequeña iteración dentro de su ciclo de vida deba su existencia a la nueva funcionalidad. 14 PT003 Documentación Este paquete contendrá toda la documentación que se precisa para realizar el proyecto. En ocasiones, será necesario realizar alguna investigación o ser partícipe de algún tipo de aprendizaje; en esos casos, las actividades de este paquete realizarán dicha labor. A0030 Identificación de fuentes y búsqueda de los datos necesarios. A0031 Lectura y aprendizaje. PT010 Captura / Identificación de requisitos y análisis Este paquete incluye el estudio y el análisis de las características y funcionalidades de IzPack para que puedan ser diseñadas e implementadas más adelante. Actividades: A0100 Estudio de las funcionalidades de IzPack. A0101 Extracción de los requisitos que se deben implementar. A0102 Análisis de los requisitos. PT020 Diseño de la implementación Este paquete de trabajo realizará el diseño de los requisitos para estudiar el modo en el que serán implementados. Actividades: A0200 Realización o modificación de la estructura de las clases. A0201 Estudio de los flujos de actividad. PT021 Revisión del diseño Revisión de los modelos realizados por si existen errores o irregularidades en ellos, con el fin de que puedan ser corregidos. Actividades: A0210 Estudio de los diseños. A0211 Corrección e introducción de los cambios (si fuese necesario). PT030 Elección de las herramientas Este paquete incluye el estudio que determina las herramientas de desarrollo que se van a utilizar a lo largo del PFC. Actividades: A0300 Consulta y estudio de posibles herramientas. A0301 Elección de las herramientas. PT031 Desarrollo de la implementación El paquete se encargará de la implementación de los diseños realizados para cada funcionalidad que se desea añadir a la aplicación. Será sin duda uno de los más costosos en el tiempo y esfuerzo invertidos, puesto que podrían aparecer errores de programación inesperados o que sean debidos a una causa difícil de detectar. A0310 Implementación de las nuevas funcionalidades. PT032 Revisión de la implementación Se considera imprescindible una revisión de la implementación que se ha hecho, con el fin de corregir los errores que se hayan podido encontrar en el código de la aplicación o mejorarlo. Actividades: A0320 Análisis del funcionamiento de los requisitos implementados. A0321 Realización de los cambios y/o mejoras oportunos (si procede). 17 PT040 Elección de las pruebas Diseño de las pruebas que se realizarán para comprobar el buen funcionamiento del sistema, escogiendo los casos más susceptibles de poseer fallos. Se realizará un listado de pruebas, detallando en cada una los posibles datos de entrada con sus correspondientes salidas esperadas. Actividades: A0400 Estudio de los requisitos. A0401 Listado de las pruebas. PT041 Ejecución de las pruebas Ejecución de las pruebas diseñadas y enumeradas en el paquete PT040. Actividades: A0410 Ejecución funcional de las pruebas. A0411 Registro de los resultados obtenidos en las pruebas. Calendario de trabajo Puesto que durante el curso 2009/2010 estaré estudiando el último curso de la doble titulación (Ingeniería Técnica en Informática de Gestión + Licenciatura en Matemáticas), no podré dedicarme de forma exclusiva al proyecto hasta, por lo menos, el día 21 de junio, momento en el que terminan los exámenes del segundo cuatrimestre. Hasta esa fecha, mi dedicación al PFC será parcial, combinándola con el estudio de las asignaturas de los cursos a los que me he referido antes. De hecho, habrá periodos en los que incluso deje de invertir tiempo en el PFC ante la proximidad de los exámenes. Esto, por tanto, hace que sea muy probable que no pueda terminar el proyecto hasta mediados de julio. La Figura 4 representa el esquema del calendario de trabajo. En naranja se representan los días de “dedicación parcial” al proyecto, en azul los días de “dedicación completa”, en blanco los días en los que, presumiblemente, no pueda dedicarme al proyecto y en verde los días a los que se puede extender la elaboración del PFC (durante los que se supone que mi dedicación será total). 18 4.2. Análisis 4.2.1. Análisis de requisitos Se pretende construir un creador de instaladores que sea capaz de permitir la construcción y configuración de cualquier tipo de instalador, independientemente del programa para el que se quiera fabricar. Es deseable que el creador de instaladores proporcione una funcionalidad similar a la que tiene la aplicación IzPack (otro creador de instaladores de código abierto); esto es, que sea capaz de permitirle al usuario: Indicar el nombre que tendrá el archivo de instalación. Definir el directorio en el que se instalará el programa. Indicar los archivos de la instalación que se copiarán en el directorio de destino, sin importar su ubicación u organización dentro del sistema en el momento de la creación del instalador. Ordenar la creación de un nuevo grupo de programas dentro del menú Inicio de Windows con los accesos directos a los archivos de la instalación que se deseen, cuyo nombre también podrá ser definido. Crear accesos directos durante la instalación a cualquier directorio o archivo en el escritorio, en la carpeta de programas, en la carpeta de aplicaciones o en la carpeta de inicio del menú Inicio. Indicar si la instalación será válida para todos los usuarios del equipo o sólo para el que ha iniciado la sesión. Proporcionar un desinstalador que gestione la eliminación de los archivos de la aplicación del sistema y de los valores del registro de Windows relacionados con ella cuando éste se ejecute, así como incorporar un icono que aparezca en el acceso directo de este desinstalador (y otros iconos que estén vinculados a otros accesos directos). Modificar el registro de Windows con los datos pertinentes relativos a la aplicación durante la instalación, o usando opciones por defecto o bien dando la posibilidad de hacerlo de forma libre, a gusto del usuario. Incluir ejecutables (archivos léeme, instalaciones externas, etcétera) que se pongan en funcionamiento al finalizar la instalación. Definir los paquetes (grupos) de archivos que crea oportunos, definiéndose paquete de archivos como un conjunto de archivos que se instalan como un todo: si uno de ellos se acaba instalando, los demás también. Además, el creador de instaladores tendrá que ser capaz de proporcionar el instalador en forma de ejecutable auto-extraíble, el cual deberá gestionar la descompresión de los archivos incluidos en la instalación, ejecutarla, modificar adecuadamente el registro de Windows y posteriormente eliminar los archivos descomprimidos (como consigue hacer IzPack). También se requiere que el instalador incorpore la instalación de la JRE de Java, con el fin de instalarla en caso de que el equipo del usuario que ejecutará la instalación final no disponga aún de ninguna versión de ella. 21 Por otro lado, el usuario que ejecute la instalación al final deberá ser igualmente capaz de modificar ciertos parámetros para definirlos como él prefiera, a saber: La ruta de instalación de la aplicación. La ubicación de los accesos directos en el escritorio. Qué paquetes (grupos de archivos) deberán instalarse. La creación y el nombre del grupo de programas dentro del menú Inicio en el que se crearán los accesos directos. Los usuarios para los cuales se instalará la aplicación (sólo el actual o todos los usuarios del equipo). La modificación de esta información deberá hacerse posible mediante la interacción con una interfaz sencilla de manejar y eficaz, que además muestre los parámetros por defecto elegidos por el usuario creador de la instalación. Tanto el proceso de creación del instalador como la instalación en sí deberán ejecutarse en un tiempo no excesivamente largo, que sea razonablemente corto. Por último, el desinstalador creado deberá revertir los cambios producidos en el equipo por el instalador de la misma aplicación, proporcionando al usuario la posibilidad de conservar el directorio de instalación y las propiedades de su configuración incluidas en los archivos de desinstalación (en cuyo caso no serán eliminados). 22 4.2.2. Casos de uso Definir nombre instalador Caso de uso: Definir nombre instalador Objetivo: Permitir al usuario creador la posibilidad de indicar el nombre que llevará el instalador. Actores: Usuario creador (UC) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: El nombre del instalador creado deberá ser el especificado por el usuario. Pasos: 1. UC: Escribe el nombre del instalador en el atributo “nombre” del elemento “instalador” del fichero instalador.xml. 2. Sistema: Guarda el nombre elegido por el usuario para asignárselo al instalador. 23 Definir archivos a copiar Caso de uso: Definir archivos a copiar Objetivo: Ofrecer al usuario creador la posibilidad de definir los paquetes de archivos que se podrán instalar. Actores: Usuario creador (UC) Precondiciones: El UC está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: Los archivos declarados por el UC estarán en disposición de ser instalados por la aplicación, dependiendo de las decisiones de los usuarios creador y final, de forma que serán copiados en el propio directorio de la instalación. Pasos: 1. UC: Escribe las rutas de las carpetas o archivos que se deben instalar dentro del elemento “instalador/fuentes/origen/archivo” del fichero instalador.xml. 2. Sistema: Guarda y trata la información introducida por el UC. Extensiones: 1.1. El UC desea copiar los archivos que ha declarado en un subdirectorio de la carpeta de instalación cuando el instalador se ponga en funcionamiento. 1.1.1. UC: Escribe la ruta relativa del subdirectorio dentro de la carpeta de instalación al que desea que se copien los archivos en el elemento “instalador/fuentes/origen/destino” del fichero instalador.xml. 1.1.2. Vuelve al paso 2 del flujo normal. 24 Definir accesos directos Caso de uso: Definir accesos directos Objetivo: Permitir al usuario creador del instalador indicar qué ficheros de la instalación podrán tener un acceso directo, así como los lugares dentro del sistema en los que se podrá ubicar. Actores: Usuario creador (UC) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Además, se han debido especificar en el XML los archivos o carpetas para los que se desean hacer los accesos directos. Pasos: 1. Extends al caso de uso “Definir archivos a copiar”. 2. UC: Indica si desea que se cree por defecto un nuevo grupo de programas, para la aplicación que se va a instalar, en el menú Inicio, dentro el atributo “incluir” del elemento “instalador/lugaresInstalacion/programas” del fichero instalador.xml. 3. UC: Define qué accesos directos quiere que se creen mediante los atributos del elemento “instalador/fuentes/origen” del paquete de archivos correspondiente, dentro del fichero instalador.xml. 4. Sistema: Guarda y trata la información introducida por el usuario. 25 Definir paquetes Caso de uso: Definir paquetes Objetivo: Permitir al usuario creador definir qué paquetes de archivos tendrá la oportunidad de instalar opcionalmente el usuario final, y permitir instalarlos a éste último. Actores: Usuario creador (UC), Usuario final (UF) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Además, se ha debido especificar en el XML qué carpetas y/o archivos podrán ser copiados en el directorio de instalación. Poscondiciones: Los paquetes de archivos que hayan sido elegidos finalmente por el usuario final y aquellos archivos que no estuvieran incluidos en ningún paquete serán instalados en el equipo, mientras que el resto no. Pasos: 1. Extends al caso de uso “Definir archivos a copiar”. 2. UC: Define los paquetes que el usuario final tendrá la opción de instalar mediante el subelemento “paquete” del elemento “instalador/fuentes/origen”, dentro del fichero instalador.xml. 3. UC: Indica si el paquete declarado será instalado por defecto mediante el atributo “defecto” del elemento “instalador/fuentes/origen/paquete”, dentro del fichero instalador.xml. 4. Sistema: Guarda y trata la información introducida por el UC. 5. Sistema: Muestra en una interfaz al UF un formulario que le permita elegir los paquetes de archivos que desea instalar, mostrando la configuración por defecto elegida por el usuario creador. 6. UF: Selecciona (o deselecciona) los paquetes de archivos. 7. Detecta y guarda la información introducida por el UF. 26 Definir accesos directos menú Inicio y escritorio Caso de uso: Definir accesos directos menú Inicio y escritorio Objetivo: Permitir al usuario que ejecutará la instalación indicar si quiere que aparezcan accesos directos en el escritorio de aquellos ficheros que los admitan, según la decisión del usuario creador, y si desea que se cree un nuevo grupo de programas que incluya los accesos directos a los ficheros de la misma aplicación que deban aparecer allí. Actores: Usuario final (UF) Precondiciones: El usuario creador ha definido previamente los archivos para los que el instalador creará accesos directos. Poscondiciones: El instalador deberá crear en las ubicaciones indicadas por el UF (escritorio, menú Inicio, ambas o ninguna) los accesos directos definidos por el usuario creador. Si se eligió la opción “menú Inicio”, además tendrá que crear el grupo de programas correspondiente dentro del menú Inicio. Pasos: 1. Herencia del caso de uso “Definir accesos directos”. 2. Sistema: Muestra en una interfaz al UF un formulario que le permita elegir instalar accesos directos en el escritorio o en el menú Inicio (o en ambas ubicaciones), mostrando la configuración por defecto elegida por el usuario creador. 3. UF: Selecciona (o deselecciona) las ubicaciones en las que desea que se creen los accesos directos. 4. Detecta y guarda la información introducida por el UF. 27 Definir usuarios finales Caso de uso: Definir usuarios finales Objetivo: Permitir al usuario creador elegir por defecto qué usuarios del equipo en el que se llevará a cabo la instalación tendrán a su disposición la aplicación que se desea instalar, así como facilitar la elección definitiva al usuario final. Actores: Usuario creador (UC), Usuario final (UF) Precondiciones: El UC está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: La instalación afectará a los usuarios definidos por el UF. Pasos: 1. UC: Define los usuarios por defecto de la instalación mediante el atributo “todos” del elemento “instalador/usuarios” del fichero instalador.xml. 2. Sistema: Guarda y trata la información introducida por el UC. 3. Sistema: Muestra en una interfaz un formulario que permita al UF decidir para qué usuarios (el actual o todos) se instalará la aplicación, mostrando la configuración por defecto elegida por el usuario creador. 4. UF: Selecciona los usuarios de la instalación. 5. Sistema: Detecta y guarda los usuarios de la instalación. 28 Definir iconos Caso de uso: Definir iconos Objetivo: Permitir al usuario creador declarar los iconos que acompañarán a los accesos directos que se hayan definido previamente. Actores: Usuario creador (UC) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd. Además, se han debido especificar en el XML qué carpetas y/o archivos tendrán asociado un acceso directo. Poscondiciones: Los iconos definidos por el usuario acompañarán a los accesos directos a los que están vinculados tras la instalación. Pasos: 1. Extends al caso de uso “Definir accesos directos”. 2. UC: Define los iconos que acompañarán a los accesos directos mediante el subelemento “icono” del elemento “instalador/fuentes/origen” del paquete de archivos correspondiente, dentro del fichero instalador.xml. 3. UC: Define el icono que acompañará al acceso directo del desinstalador mediante el subelemento “icono” del elemento “instalador/desinstalador”, dentro del fichero instalador.xml. 4. Sistema: Guarda y trata la información introducida por el UC. Extensiones: 3.1. El UC no define ningún icono para el acceso directo del desinstalador. 3.1.1. UC: Deja vacío el subelemento “icono” del elemento “instalador/desinstalador”. 3.1.2. Vuelve al paso 4 del flujo normal. 29 Definir ruta instalación Caso de uso: Definir ruta instalación Objetivo: Permitir al usuario creador elegir la ruta de instalación en la que por defecto se copiarán los archivos de la aplicación que se desea instalar, así como facilitar al usuario final la elección definitiva de esta ruta. Actores: Usuario creador (UC), Usuario final (UF) Precondiciones: El usuario creador está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: El instalador deberá copiar los archivos de la instalación en el directorio indicado. Pasos: 1. UC: Define la ruta en la que se copiarán los archivos de la instalación en el subelemento “destino” del elemento “instalador/lugaresInstalacion” del fichero instalador.xml. 2. Sistema: Guarda y trata la ruta introducida por el UC. 3. Sistema: Muestra en una interfaz al UF un campo con el nombre de la ruta elegida por defecto por el UC, de modo que el UF pueda cambiarla si lo desea. 4. UF: Cambia, si así lo desea, la ruta de instalación. 5. Sistema: Detecta y guarda la ruta de la instalación. 30 Definir grupo programas Caso de uso: Definir grupo programas Objetivo: Permite al usuario creador asignar un nombre por defecto al nuevo grupo de programas en el que se instalarán los accesos directos que se hayan definido para los ficheros de la instalación en caso de que el usuario final ordene crearlo, así como al usuario final elegir el nombre definitivo de este grupo de programas en el que se copiarán finalmente los accesos directos. El nombre seleccionado será también el del directorio de instalación. Actores: Usuario creador (UC), Usuario final (UF) Precondiciones: El usuario creador está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: El instalador creará los accesos directos especificados en el grupo de programas determinado por el UF. Pasos: 1. UC: Indica el nombre que llevará por defecto el grupo de programas que se creará durante la instalación en el menú Inicio (que será el mismo que el de la carpeta de instalación) en el elemento “instalador/lugaresInstalacion/programas” del fichero instalador.xml. 2. Sistema: Guarda y trata los datos introducidos por el UC. 3. Sistema: Muestra al UF el grupo de programas elegido por defecto, de tal forma que lo pueda cambiar. 4. UF: Elige el nombre del grupo de programas (bien sea uno nuevo u otro existente) del menú Inicio en el que se instalarán los accesos directos. 5. Detecta y guarda el grupo de programas seleccionado. 31 Definir modificación registro Caso de uso: Definir modificación registro Objetivo: Permitir al usuario creador definir el modo en el que se modificará el registro de Windows tras la instalación de la aplicación. Actores: Usuario creador (UC) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: El instalador deberá modificar el registro de Windows de acuerdo a la información suministrada por el UC. Pasos: 1. UC: Escribe “Yes” en el atributo “modificar” del elemento “instalador/lugaresInstalacion/registro” del fichero instalador.xml. 2. UC: Define las modificaciones que se deberán llevar a cabo en el registro de Windows durante la instalación mediante los atributos y subelementos pertenecientes a los subelementos “instalacion” y “desinstalacion” del elemento “instalador/lugaresInstalacion/registro” del fichero instalador.xml. 3. Sistema: Guarda y trata los datos introducidos por el UC. Extensiones: 1.1. El UC no desea realizar ninguna modificación en el registro. 1.1.1. UC: Escribe “No” en el atributo “modificar” del elemento “instalador/lugaresInstalacion/registro” del fichero instalador.xml. 1.1.2. Fin del caso de uso. 2.1. El UC desea personalizar la modificación del registro. 2.1.1. UC: Define las modificaciones que se deberán llevar a cabo en el registro de Windows durante la instalación mediante los atributos pertenecientes al subelemento “customize” del elemento “instalador/lugaresInstalacion/registro” del fichero instalador.xml. 2.1.2. Vuelve al paso 3 del flujo normal. 32 Definir archivos auto-ejecutables Caso de uso: Definir archivos auto-ejecutables Objetivo: Dar la oportunidad al usuario creador de incluir en la instalación aquellos archivos externos auto-ejecutables que se deberán ejecutar en el transcurso de ésta (otras instalaciones, ficheros de texto, etcétera). Actores: Usuario creador (UC) Precondiciones: El usuario está en condiciones de editar un fichero de nombre instalador.xml, que debe ser acorde a lo especificado en el fichero instalador.dtd o instalador.xsd. Poscondiciones: El instalador deberá ejecutar al final de la instalación los autoejecutables definidos por el UC. Pasos: 1. UC: Define los archivos que se ejecutarán al final de la instalación mediante el elemento “instalador/ejecutable” del fichero instalador.xml. 2. UC: Para cada uno de los archivos ejecutables, indica (si fuera necesario) con qué programa se abre mediante el atributo “prog” del elemento “instalador/ejecutable”. 3. Sistema: Guarda y trata la información introducida por el UC. 33 Ejecutar instalador Caso de uso: Ejecutar instalador Objetivo: Llevar a cabo la instalación de la aplicación, de modo que se cree un archivo que gestione su posible desinstalación posterior. Actores: Usuario final (UF) Precondiciones: El instalador ha sido creado con las características definidas por el usuario final y el usuario creador. Poscondiciones: Se llevará a cabo la instalación. Pasos: 1. UF: Hace doble clic sobre el fichero auto-ejecutable de la instalación. 2. Sistema: Descomprime los archivos a copiar, lleva a cabo la instalación y gestiona la eliminación de los archivos que fueron necesarios durante el proceso. 34 4.2.3. Diagrama de casos de uso Figura 6: Diagrama de casos de uso 35 4.3. Diseño En este apartado se describirán las soluciones y los procedimientos que se van a adoptar para satisfacer los requisitos descritos en el análisis, referentes a la aplicación que estamos desarrollado: el creador de instaladores. La solución propuesta será válida solo para algunos de los sistemas operativos más recientes de Windows. Esta solución está basada en la construcción de dos clases Java: Creador_instaladores y Construct. La primera clase es la que contiene al método main, por lo que deberá hacer referencia a la clase Construct (cuyos métodos servirán para llevar a cabo la ejecución completa del programa) y será la encargada de dirigir el flujo principal del programa. Además, esta clase tendrá que leer los datos que se encuentren en el fichero Instalador.xml, los cuales definirán la configuración de la instalación que haya elegido el usuario creador. Por otro lado, la clase Construct se encargará de la construcción, compilación y ejecución de los ficheros necesarios para poner en marcha el instalador. Estas dos clases serán descritas con mucho más detalle posteriormente en esta sección. La filosofía de trabajo consiste en la creación y compilación del código necesario a partir de estos ficheros iniciales para conseguir la construcción del instalador, en forma de archivo auto-extraíble fácilmente utilizable por el usuario final. Esto significa que los ficheros descritos hasta ahora elaborarán otros ficheros y archivos “extra”, cuya compilación y ejecución dará lugar a la ejecución del instalador definitivo. A pesar de que el lenguaje de programación preferido para realizar este proyecto es Java (debido a que es fácil de compilar y ejecutar, además de ser muy conocido), el lenguaje del código generado variará en función de la necesidad o la comodidad de lo que se quiera hacer en cada momento: cuando una tarea sea inviable o muy difícil de realizar en Java, se creará código en otros lenguajes de programación que nos proporcionen alternativas posibles o más sencillas con el fin de conseguir su ejecución sin más problema. Además del lenguaje Java (el predeterminado), se utilizará C++ y el propio lenguaje de la shell de Windows (pudiéndose de este modo construir archivos .bat, ejecutables por lotes). Además de estos archivos, se deberán aportar otros tres más para obtener la correcta y completa ejecución del proyecto. Uno de ellos ya ha sido mencionado: el Instalador.xml, que se encargará de recoger la información de la configuración de la instalación definida por el usuario creador. Puesto que es el propio usuario creador el que debería encargarse de su edición, debido a nuestra decisión de no implementar ninguna interfaz para este usuario, nos veremos obligados a incluir en nuestra aplicación una plantilla (de nombre plantilla.xml) que muestre con la mayor fidelidad posible la estructura del XML asociado a este archivo (la cual se describe con los ficheros Instalador.dtd e Instalador.xsd, y con el esquema XML-Schema correspondiente). 36 Otro archivo “extra” que se incluirá es el llamado Make.bat, archivo ejecutable por lotes de Windows que añadirá al CLASSPATH las rutas requeridas para que se ejecute el programa, ejecutará los archivos iniciales antes descritos (Creador_instaladores.class y Construct.class) y completará la ejecución de algunas tareas de creación y compresión de archivos necesarias para la creación del archivo que llevará a cabo la instalación definitiva. El tercer archivo, InterfazGrafica.java, proporcionará el código fuente de la interfaz del usuario final. Este código se encargará de guardar en las variables de la clase Instalador la información introducida por el usuario que ejecuta el instalador, de modo que le permitirá cambiar algunos aspectos de la configuración elegida por defecto por el usuario creador del instalador de forma cómoda. La clase InterfazGrafica se compilará a la vez que la clase Instalador, por lo que no es necesario incluir en la carpeta de nuestra aplicación los ficheros binarios referentes a la clase InterfazGrafica. Sin más dilación, pasemos a estudiar con más detenimiento las funciones desempeñadas por las clases mencionadas, así como las de los archivos construidos a partir de ellas. 4.3.1. Descripción de la clase Creador_instaladores Clase que contendrá al método principal y leerá los datos almacenados en el fichero Instalador.xml. Por esto último, es necesario que importe las librerías org.jdom, org.jdom.input y org.jdom.output. Además, usará la clase SAXBuilder con el fin de cargar en memoria el árbol de elementos del fichero XML que necesita leer. Después de cargar el XML, la clase gestionará la lectura de los datos pertinentes. Éstos serán almacenados en diferentes variables para ser utilizados posteriormente en el constructor de la clase Construct. Una vez creado un objeto de esta clase, se invocará a los métodos que posea, ya que éstos serán los encargados de construir el código del instalador y del desinstalador, así como del resto de archivos que se precisan para compilarlos, comprimirlos, ejecutarlos, etcétera. Los métodos de esta clase se describen a continuación: leerOrigen (Document) devuelve List: devuelve una lista que contiene a los archivos que se desean instalar, así como la ruta dentro del directorio de instalación en la que se copiarán, el icono asociado a su acceso directo (si existe) y el paquete de archivos al que pertenecen (en caso de que se declare). leerDestino (Document) devuelve String: devuelve la ruta por defecto en la que el directorio de la instalación será creado. leerInstalador (Document) devuelve String: devuelve el nombre que tendrá el instalador. leerPrograma (Document) devuelve String: devuelve el nombre que tendrá por defecto el grupo de programas dentro del menú Inicio en el que se crearán los accesos directos del programa que se instalará. Además, también será el nombre que recibirá la carpeta de instalación. 37 incluirPrograma (Document) devuelve String: devuelve “Yes” si el usuario creador desea ordenar por defecto la creación de un grupo de programas en el menú Inicio en el que incluir accesos directos; “No”, en otro caso. leerUsuarios (Document) devuelve String: devuelve “Yes” si se desea que la aplicación se instale por defecto para todos los usuarios del equipo; “No”, si tan solo se requiere para el usuario que ha iniciado la sesión. leerDesinstalador (Document) devuelve String: devuelve la ubicación del icono con el que se representará el acceso directo del instalador. En caso de que el usuario creador no haya definido ningún icono para el desinstalador, devolverá null. leerRegistro (Document) devuelve List: devuelve una lista con toda la información relativa a la modificación que se hará del registro una vez haya sido iniciada la instalación. leerEjecutables (Document) devuelve List: devuelve una lista con los ejecutables que se deberán inicializar una vez finalizada la instalación. Estos ejecutables pueden ser instalaciones de programas complementarios, ficheros de texto (estilo readme), etc. Para cada ejecutable, se incluye el programa con el que se deben abrir dichos archivos (si fuese necesario). 4.3.2. Descripción de la clase Construct Esta es la clase más importante de la aplicación. Sus funciones son las que a continuación se muestran: Generar el código de los archivos Instalador.java y Desinstalador.java. Generar el ejecutable .exe que comprimirá todos los archivos y ejecutará la instalación. Para ello, creará complementariamente un archivo que colabore en la creación del ejecutable: temp.bat. Generar los ficheros manifest. Estos ficheros son muy útiles cuando se van a construir ficheros .jar que contendrán las clases que se ejecutarán. Su función es indicar cuál es la clase que contiene el método principal para que sea ejecutada cuando se invoque al jar (bien mediante doble clic o por línea de comandos). Compilar los archivos Instalador.java y Desinstalador.java. Esto provocará la aparición de dos ficheros .class, con el código binario de estas dos clases. Generar el archivo install.properties, necesario para guardar las preferencias de instalación del usuario final. Esto permitirá al desinstalador encontrar la información necesaria para revertir los cambios producidos en el sistema durante la instalación. El archivo install.properties también servirá para mostrar al usuario final los parámetros de la instalación elegidos por defecto por el usuario creador. Vamos a describir qué hace exactamente cada método de esta clase, comenzando por el constructor. 38 Constructor: Se encarga de recoger la información proveniente de la clase Creador_instaladores y de almacenarla en las variables adecuadas. En primer lugar, construye una lista que almacenará la información de los archivos que se usarán en la instalación. Para ello, usará varios vectores de datos: -Un vector para almacenar qué archivos tendrán acceso directo en el grupo de programas que se cree para la aplicación durante la instalación, otro para indicar cuáles lo tendrán en el escritorio y otros tres más para indicar lo mismo con respecto a la carpeta de inicio, la carpeta de programas y la carpeta de aplicaciones, todas pertenecientes al menú Inicio. Estos vectores almacenarán un booleano por cada archivo, que valdrá true si el archivo va a tener un acceso directo en el lugar especificado y false en caso contrario. El orden de representación de los archivos en estos vectores coincidirá con el que proviene de la lista definida en el constructor; de esta forma, quedará completamente determinado qué booleanos harán referencia a qué archivos. -Un vector para almacenar la ruta (en formato String) de los iconos que se usarán para los accesos directos de estos archivos. Los archivos para los que no se haya definido ningún acceso directo llevarán un null en su correspondiente componente del vector. -Otro vector para indicar la ruta de los archivos dentro del directorio de instalación. Esta información es útil en determinados casos para copiar archivos dentro de un subdirectorio de la carpeta de instalación. Nuevamente, si esta información no es necesaria para un determinado archivo, su correspondiente componente en este vector valdrá null. -Dos vectores más para almacenar los paquetes de archivos que el usuario final tendrá la opción de instalar y cuáles de esos paquetes se instalarían por defecto, según la decisión del usuario creador. Tras esto, el constructor guarda en los atributos de la clase el resto de la información de la configuración del instalador: la ruta de la carpeta de instalación, el nombre del instalador, el nombre del grupo de programas del menú Inicio relativo a la aplicación que se deseará instalar (que será el mismo que el que tenga la carpeta de instalación), para qué usuarios se instalará la aplicación (todos o solamente el que haya iniciado sesión), si se creará un nuevo grupo de programas para la aplicación en el que incluir accesos directos, el icono que acompañará al acceso directo del desinstalador (null si no existiese tal icono) y los programas que se ejecutarán como complemento después de la instalación (instaladores externos, archivos readme, etcétera). Conviene recordar que algunos de estos parámetros no son definitivos, pues serán revisados por el usuario final (el que ejecute la instalación en última instancia). Además, el constructor elaborará a partir de esta información las rutas dentro del sistema del menú Inicio, del escritorio y de las carpetas de aplicaciones, inicio y del grupo de programas de la aplicación dentro del menú Inicio. 39 Por último, el constructor construye las estructuras que almacenarán la información sobre la modificación del registro de Windows. Para ello, comprueba en primer lugar que el usuario desea modificar el registro a partir del atributo correspondiente al fichero XML leído: si su valor es “Yes”, construirá las estructuras necesarias para almacenar esta información; si es “No”, terminará en ese momento su labor. En caso de que se desee modificar el registro, el constructor contará con un vector de cadenas de texto cuyas componentes guardarán los datos relativos a los siguientes elementos y atributos del fichero Instalador.xml: Componente 0 1 2 3 4 5 6 7 8 Elemento Instalacion Desinstalacion Desinstalacion Desinstalacion Desinstalacion Desinstalacion Desinstalacion Desinstalacion Desinstalacion Atributo InstallDir NoModify NoRepair DisplayVersion DisplayIcon URLInfo HelpLink Publisher URLUpdate Valor Yes/No Yes/No Yes/No version icon url help pub update Tabla 1: Elementos y atributos para modificar el registro Esto significa que las componentes 0, 1 y 2 podrán guardar los valores “Yes” o “No” solamente, mientras que el resto almacenarán la cadena que contengan los elementos del XML indicados en la columna “Valor”. El resto de la información referente a la modificación del registro habrá quedado almacenada en un atributo de tipo List junto a lo que acabamos de describir y será tratada más adelante en otros métodos. generarInstalador: Su única (aunque trascendental) función es elaborar el código de la clase Instalador. Es por eso que el método usa una variable de tipo File, con la cual crea el fichero de nombre Instalador.java, y otra de tipo BufferedWriter asociada a la anterior con la que escribe en el fichero que ha creado. Estudiemos el código que ejecutará la clase Instalador (es evidente que dicho código dependerá de los datos de configuración almacenados en la clase Construct y en el fichero de configuración install.properties, que veremos más adelante). En primera instancia, su método principal guarda los paquetes de archivos de instalación y genera los valores (true o false) del vector que determinará qué paquetes se instalarán finalmente. Estos valores serán true al principio y únicamente se cambiarán a false en el momento en el que el usuario final decida no instalar el correspondiente paquete. Lo último que hace el método principal es invocar a la interfaz gráfica con la que el usuario final interactuará y que veremos con más detalle en el apartado 4.3.6. Interfaz del usuario final. 40 La interfaz gráfica llamará al método instalar de la clase Instalador, una vez ha modificado los atributos de esta clase con los datos introducidos por el usuario final. Inicialmente, el método crea el directorio de instalación con sus diferentes subcarpetas: una con los archivos de la aplicación, otra con los iconos de los accesos directos (de nombre Iconos) y otra con el desinstalador (de nombre Desinstalador). Después, extrae el fichero de configuración de la instalación install.properties del archivo Instalador.jar y lo añade al jar del desinstalador, Desinstalador.jar, con el nombre desinstall.properties. Acto seguido, procede a copiar los archivos pertinentes en cada subcarpeta, comprobando antes qué paquetes de archivos deben instalarse: los iconos, en Iconos; el jar con el desinstalador, en Desinstalador; y el resto de archivos definidos, en la subcarpeta restante. Para cumplir con todos estos cometidos, la clase cuenta con dos métodos privados: copiarDirectorio y copiarFichero, de modo que pueda crear o copiar cualquier directorio, incluyendo sus subdirectorios y ficheros, de forma recursiva. Tras esto, crea los accesos directos. Para ello, necesita la ayuda de un programa externo, Shortcut.exe, que permite la creación de accesos directos desde la línea de comandos. Este programa ofrece muchas funcionalidades, por lo que dispone de muchos parámetros de entrada. Nosotros usaremos tan solo tres: el que indica cuál será la ruta completa del acceso directo (incluyendo el nombre), el de la ruta del archivo al que apunta el acceso directo y el de la ruta en la que está situado el icono con el que se mostrará el shortcut (si éste existiera). Puesto que estamos haciendo uso de un programa ajeno al propio que se está ejecutando en Java (por tanto, en un hilo diferente del proceso), hemos de obligar al sistema a esperar a la finalización del programa Shortcut.exe para proseguir con la ejecución del código de la clase cada vez que se cree un acceso directo. Posteriormente, la clase Instalador procede con la modificación del registro de Windows. Para ello, necesita hacer varias llamadas al sistema, bien para crear nuevas entradas en el registro o para cambiar las ya existentes en él. Con este fin, los parámetros que nuestra aplicación pasa a la línea de comandos son: la ruta y la clave del registro que se modificará, el valor (en forma de cadena de texto) que tendrá dicha clave y el tipo de dato que representa al formato del valor asignado a la clave (por defecto, REG_SZ). Al igual que pasaba con los accesos directos, la llamada al sistema implica la ejecución de un nuevo hilo dentro del proceso, por lo que vuelve a ser necesario esperar a su finalización para continuar con la ejecución del código de la clase. Lo mismo sucede con los ejecutables (instalaciones externas, etcétera) que se pondrán en marcha tras la instalación: habrá que esperar a que termine su ejecución. Este será el último deber de la clase Instalador. 41 Es preciso indicar que los archivos y accesos directos que se crean, así como la modificación del registro, dependen de la información almacenada en los vectores definidos por el constructor. No obstante, los datos del registro que el usuario creador define libremente (relativos al elemento customize del fichero XML) y los programas que se ejecutan tras la instalación (provenientes del elemento ejecutable de Instalador.xml) no quedan recogidos en ningún vector. Esta información, que es almacenada en dos estructuras de tipo List en el constructor, será extraída directamente de estas listas en el método generarInstalador que acabamos de estudiar. La razón por la que se ha tomado esta decisión es que las cadenas de texto almacenadas se escribirán sin ningún tipo de tratamiento adicional en el fichero Instalador.java, por lo que no se necesita de ninguna estructura que las recoja. Esto no sucede con los demás datos, debido a motivos de comodidad durante el desarrollo de la programación o al tratamiento y mutación de la información que representan. Hay que recordar que aquellos parámetros que puedan ser modificados por el usuario final no se escribirán de forma directa en el fichero Instalador.java, sino que serán parametrizados por diferentes variables que lean en tiempo de ejecución la información almacenada en el fichero de configuración que se creó a tal efecto. Los métodos que se encargan de dar valores a los atributos de la clase Instalador serán invocados por la interfaz gráfica cuando el usuario final inicie la instalación. generarDesinstalador: Método que genera el fichero Desinstalador.java. Evidentemente, se trata del fichero que contiene a la clase Desinstalador, la cual posee un método cuya labor será eliminar del sistema todos los archivos y registros creados por la clase Instalador relativos a la aplicación instalada. Al igual que ocurría con el método generarInstalador (así como con los demás métodos que faltan por describir), este método usa una variable de tipo File, con la cual crea el fichero de nombre Desinstalador.java, y otra de tipo BufferedWriter asociada a la anterior, con la cual escribe en el fichero que ha creado de acuerdo a la configuración establecida por el usuario creador del instalador. El método principal se encarga de cargar el fichero desinstall.properties que recoge la información que necesita el desinstalador para revertir los cambios producidos por el instalador y de recoger esta información en los atributos de la clase. Por otro lado, también muestra al usuario final una interfaz para confirmar la desinstalación y que le permita indicar si desea que se elimine el directorio de instalación junto con los archivos del desinstalador. Esto se recoge en una variable de tipo booleano, que a su vez se pasa como parámetro al método desinstalar, que es el encargado de llevar a cabo la desinstalación propiamente dicha. 42 El método desinstalar borra, en primer lugar, todas las carpetas y archivos creados previamente durante la instalación de forma recursiva (de modo que es capaz de eliminar todas las subcarpetas sin tener que hacer referencia a cada una de ellas explícitamente en el código). Para ello, se ayuda del método recursivo borrarDirectorio. Este método recibe como parámetro la ruta de un directorio y elabora una lista con los archivos y directorios que posee. Después, va recorriendo uno a uno los elementos de esta lista, de modo que si es detectado como un archivo, lo borra directamente, y si es un directorio, se invoca a sí mismo enviándolo como parámetro. Tras esto, el método principal se encarga de eliminar las claves del registro relacionadas con la aplicación que se está desinstalando. Tanto estas claves como los archivos anteriores se han podido detectar gracias a los vectores atributos de la clase Construct que fueron definidos en el constructor, así como al fichero de configuración creado previamente. Por último, si el usuario final así lo quiso, el método desinstalador invoca al método forzarEliminacion, que es utilizado para borrar la carpeta de instalación cuando se han eliminado todos los archivos y subcarpetas que contenía, a excepción del fichero Instalador.jar y las carpetas en las que se encuentra. La estricta necesidad de este método se debe a que un fichero Java (como Instalador.jar) no puede eliminarse a sí mismo (tendría que cerrarse primero), por lo que se ha de recurrir a la creación de un archivo bat (ejecutable por lotes) capaz de auto-borrarse y que, a su vez, borre a los directorios anteriores; si simplemente intentáramos borrar recursivamente la carpeta de instalación, los archivos que estuvieran abiertos no se podrían eliminar. De este modo, forzarEliminacion crea un fichero de nombre destruir.bat en el directorio C:\ que, por este orden, o o o o Mientras exista, intenta borrar (y al final, borra) el fichero Desinstalador.jar. Borra la carpeta contenedora de Desinstalador.jar, Desinstalador. Borra la carpeta de instalación. Se borra a sí mismo. Tras la construcción de este archivo, el método forzarEliminacion hace que se ejecute en la línea de comandos. Dicho método finaliza cuando se ha hecho efectiva esta última acción. Cabe recordar que, al igual que ocurría con el método generarInstalador, éste tampoco escribe directamente los parámetros configurables por el usuario final en el fichero Desinstalador.java; en su lugar, crea variables que harán referencia a esa información, de modo que la clase cuente con ella en tiempo de ejecución. generarEjecutable: Método que genera el ejecutable .exe que comprimirá todos los archivos y ejecutará la instalación cuando el usuario final ponga el fichero auto-ejecutable en funcionamiento mediante doble clic. 43 En primer lugar, el método crea un fichero de nombre arch.cpp. Éste comprobará cuando se inicialice la instalación si está instalada en el equipo alguna versión de la máquina virtual de Java, de modo que, de no ser así, instale la Versión 6 – Actualización 18 en este equipo (deteniéndose la instalación hasta que este proceso termine). Tras esto, iniciará la instalación, ejecutando el Instalador.jar. Después, se genera el archivo temp.bat, que ejecutará el resto de comandos para construir el ejecutable final: añadirá al path la ruta del programa para comprimir los archivos (que será el 7-Zip), compilará el archivo .cpp creado anteriormente (el programa ejecutable resultante de la compilación se llamará Setup.exe), creará los jars correspondientes al instalador y al desinstalador (incluyendo como parámetro los ficheros de manifiesto que se habrán elaborado), creará un fichero comprimido que incluya a todos los archivos necesarios para la instalación (de nombre InstallFiles.7z), eliminará los archivos añadidos al fichero comprimido, creará el ejecutable final y borrará el .7z y a él mismo. La razón por la que se eligió el 7-Zip como programa de compresión de los archivos se debe a la posibilidad que ofrece de crear un archivo auto-ejecutable y autoextraíble desde la línea de comandos. Para la correcta ejecución de este proceso, es necesaria la existencia de un par de archivos en el mismo directorio de la aplicación que estamos desarrollando: el 7zS.sfx, para crear el auto-extraíble, y el config.txt, donde se le indica al auto-extraíble cuál es el fichero que debe ejecutar (en nuestro caso, el Setup.exe, consecuencia de la compilación del archivo arch.cpp). Por otro lado, la explicación de por qué se determinó utilizar el lenguaje de programación C++ a la hora de componer el arch.cpp se debe a las facilidades que proporciona C++ para crear archivos ejecutables (algo que en Java es más complicado). generarManifest: Los ficheros de manifiesto, o manifest, sirven para ejecutar una aplicación Java comprimida en un jar. Estos ficheros contienen el nombre de la clase que contiene al método principal (es decir, la que debe ejecutarse). El método generarManifest se encarga de la elaboración de estos ficheros de manifiesto, así como de la compilación de los ficheros Instalador.java y Desinstalador.java a los que hacen referencia. generarInstallConfig: Creará el fichero de configuración; lo que escriba en él dependerá en primera instancia de la configuración que haya elegido inicialmente el usuario creador. Este fichero permitirá a la postre que el usuario final sea capaz de cambiar la configuración decidida por el usuario creador (pues no tendrá por qué coincidir con la suya). Todas las claves presentes en este fichero tomarán, en un primer momento, los valores recogidos en la clase Instalador a excepción de la relativa a los accesos directos en el escritorio, que tomará siempre por defecto el valor true. Las claves y su descripción quedan recogidas en la siguiente tabla. 44 Clave Descripción <Nombre_paquete> Paquete a instalar. Puede haber 10 a lo sumo. Tomará valor true si se desea instalar y false en caso contrario. Ruta Ruta dentro del sistema en la que se ubicará la carpeta de instalación. Programas Nombre de la carpeta de instalación y del grupo de programas de la aplicación, en caso de que se acabe creando. Todos Usuarios para los que será válida la instalación. Tomará valor true si es para todos los usuarios y false en caso contrario. Inicio Especifica si se creará un nuevo grupo de programas para la aplicación. Tomará valor true si el usuario desea crearlo y false en caso contrario. Escritorio Especifica si se crearán accesos directos en el escritorio. Tomará valor true si así se desea y false en caso contrario. Su valor por defecto siempre será true. Tabla 2: Claves del fichero de configuración y su descripción 4.3.3. Descripción del archivo Make.bat En los anteriores métodos hemos creado un archivo, temp.bat, pero en ninguno de ellos lo hemos ejecutado. Además, hemos usado código en C++, pero en ningún momento hemos añadido al path ningún programa que sea capaz de compilarlo. Por otro lado, el usuario creador del instalador necesitaría ejecutar de una manera sencilla la clase Creador_instaladores, con el fin de, una vez definida la configuración de la instalación, crear el archivo auto-ejecutable (y auto-extraíble) correspondiente. Pues bien, esas serán las funciones del archivo Make.bat: lo único que tendrá que hacer el usuario creador para construir su instalador es hacer doble clic sobre este archivo. Estará situado en el mismo directorio de la aplicación desarrollada (junto, por ejemplo, a los archivos Config.txt y 7zS.sfx del programa 7-Zip). 45 4.3.4. Relaciones entre los archivos de la aplicación La siguiente ilustración (Figura 7) muestra todas las relaciones que se darán entre los diferentes archivos que formarán parte del proceso de creación del instalador. Figura 7: Diagrama de colaboración entre los ficheros de la aplicación 4.3.5. Interfaz del usuario creador Descripción El medio mediante el que el usuario creador podrá construir su instalador consistirá en un fichero XML que deberá ser acorde al XML-Schema representado por el siguiente esquema (Figura 8). 46 Figura 8: XML-Schema del fichero Instalador.xml Este otro esquema (Figura 9) recoge la información detallada del elemento del XML lugaresInstalacion presente en el esquema general anterior. Figura 9: XML-Schema del elemento lugaresInstalacion 47 Para mayor comodidad, el usuario creador dispondrá de una plantilla escrita en lenguaje XML cuyo contenido será válido para el XML-Schema anterior. Las modificaciones introducidas por el usuario creador al editar dicho fichero (que deberá nombrarse como Instalador.xml) deberán seguir respetando la especificación del XML-Schema aquí descrito. Es necesario indicar que se consideró seriamente dentro de este proyecto la realización de una interfaz que permitiera al usuario creador construir su instalador sin necesidad de escribir ninguna línea de código XML, pero finalmente se desechó debido principalmente a dos razones: Las mejoras que se obtendrían en caso de implementar la interfaz no compensan el gran esfuerzo que supondría su creación. Hay que tener en cuenta que habría que crear pantallas que permitieran al usuario la creación de accesos directos, la posibilidad de modificar el registro de Windows, indicar qué archivos se copiarán en el directorio de instalación… lo cual se puede indicar de un modo mucho más sencillo (y de una sola vez) en el fichero XML. Además, no es descabellado suponer que el usuario creador tendrá los conocimientos necesarios para editar sin problemas un fichero XML con las características descritas, por lo que la solución adoptada no supondría un contratiempo demasiado importante para él. Precondiciones El usuario creador encontrará a su disposición un fichero de nombre plantilla.xml que cumplirá las especificaciones definidas en el archivo Instalador.xsd e Instalador.dtd. Por tanto, el código XML incluido en este archivo será acorde al esquema mostrado anteriormente en este documento. Además, el usuario creador encontrará un pequeño manual de instrucciones que le permita editar adecuadamente el fichero Instalador.xml y trabajar con el programa. Poscondiciones Las modificaciones introducidas por el usuario creador al editar el anterior documento deberán respetar la especificación del XML-Schema descrito. Por otra parte, la aplicación deberá recoger la información introducida por el usuario creador y guardarla con el fin de mostrarla al usuario final para que pueda ser modificada (en unos casos) o usarla directamente como parámetro cuando se construya el instalador (en otros). Las características que deberá tener el fichero Instalador.xml una vez haya sido editado están definidas en el manual de instrucciones del creador de instaladores, el cual se mostrará en el Anexo I de este proyecto. 48 Diagrama de estados Figura 13: Diagrama de estados de la interfaz del usuario final 4.4. Implementación A continuación, a lo largo de este apartado, se indicarán cuáles fueron las principales dificultades que hubo que superar durante el desarrollo de este proyecto con respecto a la implementación de los requisitos según la estrategia descrita en la fase de diseño, tanto relativas a la programación como a las técnicas específicas empleadas. En primer lugar, es conveniente comentar que solamente encontrar un diseño adecuado para la construcción del creador de instaladores fue un tarea, de por sí, compleja, ya que requirió, desde el primer momento, el estudio del código de otros creadores de instaladores (como IzPack), así como de las funcionalidades que son capaces de ofrecer. Algunas de las soluciones y técnicas adoptadas en este software fueron tenidas en cuenta a la hora de construir nuestra aplicación; sin embargo, la mayoría de las ideas empleadas en la elaboración del proyecto son completamente originales y son fruto de la investigación surgida a raíz de los intentos de implementación de cada requisito. Es decir, la construcción de gran parte de la aplicación se debe a un proceso que bien puede dividirse en dos partes: 1. Estudio del siguiente requisito que se implementará. 2. Obtención del diseño de la implementación de este requisito, basada en la investigación y en el estudio de la situación. En las siguientes líneas especificaremos con detalle los problemas encontrados y las soluciones que se llevaron a cabo para solventarlos, así como los aspectos más importantes a destacar con respecto a la implementación. Una de las principales dificultades que se tuvieron que afrontar (además, de modo constante) fue todo lo relacionado con las rutas del PATH y del CLASSPATH, debido, sobre todo, al desconocimiento que tenía acerca de ellos al iniciar el proyecto y a la falta de experiencia con respecto a su manejo y sintaxis. Esto provocaba que, cada vez que quería ejecutar una clase Java ubicada en cualquier directorio del sistema o cualquier programa necesario para el correcto funcionamiento de la aplicación, acabara obteniendo un error. Finalmente, la ruta del PATH se modificó en el fichero Make.bat con el fin de poder utilizar el programa Dev-Cpp para la compilación y ejecución del código C++ utilizado en la aplicación, además de en el fichero temp.bat para la ejecución del programa 7-Zip para la comprensión de los archivos de la instalación y la creación del fichero auto-ejecutable. Por su parte, la ruta del CLASSPATH se cambió en el propio Make.bat con el fin de localizar los .class de la aplicación y el jdom.jar, necesario para leer el fichero XML de configuración. 54 Aunque menor, otro de los problemas que me encontré inicialmente fue la lectura del fichero XML de configuración. Como he comentado antes, esto se logró gracias a JDom. Sin embargo, nuevamente el desconocimiento de esta herramienta provocó que aparecieran errores en la aplicación, debidos sobre todo al hecho de que, en determinadas ocasiones, trataba de leer subelementos del XML no existentes. Por ejemplo, si no se incluía en el XML el subelemento “desinstalador” (porque no se asignaba ningún icono al desinstalador) y la aplicación trataba de leer dicho subelemento, se producía un error. Ante este problema se adoptaron tres posibles soluciones, que se pasan a describir a continuación: o Mantener el subelemento en el XML con una cadena vacía de modo que la aplicación pueda leerlo sin que se produzcan errores, aunque no proporcione ninguna información. o Incluir en el elemento padre un atributo (de tipo “Yes/No”) que indique si hay que tener en consideración la información almacenada en sus hijos. o Hacer que la aplicación lea un subárbol del XML que incluya a los elementos que puedan omitirse en determinadas ocasiones, de modo que sea la propia lógica de la aplicación la que determine qué elementos son los que finalmente se incluyen. En función de la situación, se eligió una solución u otra, atendiendo principalmente a la probabilidad de que el subelemento se pudiera omitir: si el subelemento iba a quedar pocas veces vacío (como es el caso del icono del desinstalador), directamente se recurría a la cadena vacía; si eran varios los subelementos que podían omitirse, se optaba por el atributo en el elemento padre; en otro caso, se consideraba la tercera opción (nótese que es la más laboriosa, tanto para el programador como para la máquina). La utilización de ficheros jar para la ejecución de los archivos Java compilados ocasionó que se invirtiera cierto tiempo en investigar acerca de cómo ejecutarlos. Los ficheros de manifiesto, que pueden entenderse simplemente como ficheros en los que se indica cuál es el archivo en el que se encuentra la clase que contiene al método principal, son los que subsanaron tal dificultad. El instalador que se va a crear deberá ser capaz de determinar para qué usuarios se tiene que instalar el programa. Esta funcionalidad se implementó mediante el uso de ‘System.getProperties(“user.name”)’, lo cual recoge el nombre del usuario actual del sistema operativo. Otro gran problema fue la creación de los accesos directos. Resulta sencillo crear un acceso directo en Windows de modo directo (con el ratón, por ejemplo), pero ¿cómo crear un acceso directo de modo programado desde la línea de comandos? En Windows no existe ningún mandato que nos permita realizar tal cosa. Los accesos directos son, en realidad, archivos que hacen referencia a otro archivo situado en cualquier ubicación, caracterizándose por tener extensión .lnk. No obstante, es obvio que para crear un acceso directo no basta con añadir esta extensión a un determinado archivo, sino que habrá que referirse al directorio en el que se encuentran el archivo base y el icono que representará tal acceso directo. 55 Tras largas horas de investigación, la solución vino dada por el uso de un programa externo capaz de crear accesos directos desde la línea de comandos, llamado Shortcut.exe, al cual basta con introducirle como parámetros los comentados más arriba. Una dificultad menor, pero difícil de solventar, es la que ocasionaba la eliminación del sistema del propio archivo de desinstalación. ¿Cómo borrar un archivo desde el mismo archivo que debe ser borrado? Todo desinstalador que se precie debería ser capaz de eliminar también los archivos relativos a la desinstalación del programa, incluidos ellos mismos. Las pruebas e investigaciones iniciales mostraron que era poco probable que, bajo cualquier circunstancia, un archivo jar se pudiera eliminar a sí mismo, y que en caso de que fuera posible, sería difícil de conseguir (habría que esperar a que el archivo se cerrara, o bien cerrarlo nosotros mismos, antes de intentar eliminarlo). Por tanto, la conclusión que se extrajo de esto fue que debía ser necesariamente otro archivo el que se encargara de eliminar el archivo jar del desinstalador. Ahora bien, del mismo modo, dicho archivo debía ser capaz de eliminarse a sí mismo. Pues bien, los archivos ejecutables por lotes de Windows (de extensión .bat) tienen esta propiedad. Por ello, la solución consistió en la creación de un script que esperara el tiempo necesario a que se cerrara el archivo jar de desinstalación, procediera a borrarlo y después, se auto-eliminara del sistema. Este script simplemente intentaba borrar el archivo reiteradas veces hasta que éste se cerraba y lo lograba, momento en el que procedía con su auto-eliminación. Hay que indicar que este script es ubicado durante la desinstalación en el directorio C:\, debido a que este directorio es muy probable que exista en el ordenador del usuario final (se trata de la carpeta que contiene habitualmente los archivos del disco duro de la máquina). Su nombre es destruir.bat. No solo la eliminación del propio desinstalador causó problemas. También otros archivos intermedios necesarios para el correcto funcionamiento de la aplicación que deben ser borrados durante el proceso de instalación ocasionaron contratiempos a la hora de ser eliminados, debido de nuevo a que la propia aplicación intentaba borrarlos antes de que se cerraran. Por razones desconocidas, con determinados archivos (no todos), la táctica de esperar hasta que éstos se cerraran no funcionaba si se programaba desde Java, por lo que se recurrió a su eliminación desde otro script (en este caso, el temp.bat). La modificación del registro de Windows es otro de los problemas que hubo que afrontar, no solo por el desconocimiento inicial acerca de para qué se utilizaba y cómo se podía cambiar, sino también por el peligro que conllevaba realizar tal acción; es recomendable no cambiar ningún valor del registro de cualquier ordenador, salvo que sea estrictamente necesario. 56 La aplicación debía ofrecer dos maneras diferentes de modificar el registro: a gusto del usuario o mediante guías, o pistas, que permitieran al usuario creador cambiar aquellos registros que más se suelen utilizar a la hora de realizar instalaciones de programas. Puesto que lo primero se puede entender desde el punto de vista de la programación como una generalización de lo segundo (para modificar el registro, hay que indicar siempre la ruta que se desea cambiar, el atributo a cambiar, el tipo de dato que se introduce y el nuevo valor que tendrá el atributo; y esos son los parámetros que se consideran en el segundo método), hubo que reestructurar parte del código (ya que, al principio, no se pensó en la posibilidad de modificar el registro a gusto del usuario), de modo que un mismo método Java sirviera para insertar en el registro datos mediante cualquiera de las dos opciones anteriores. El método Java que se encarga de tal tarea es la acción insertarEnRegistro. Como mejora con respecto a ciertos creadores de instaladores, como IzPack, el programa añade una nueva funcionalidad: es capaz de proporcionar al usuario final un ejecutable en lugar de un simple archivo jar, de modo que si el usuario final tiene instalada la JRE de Java en su equipo, el .exe ejecuta directamente el jar, y si no, instala antes Java. Para lograr este objetivo, la aplicación crea durante la instalación un archivo C++, llamado arch.cpp, el cual comprueba si existe alguna versión de la JRE de Java instalada en la máquina haciendo una llamada al sistema con el mandato: pid=system("java -version>nul 2>&1"); En caso de que exista alguna versión, system devolverá el valor 0; en otro caso, devolverá un valor distinto de 0. Así, podremos distinguir de forma unívoca si realmente está instalado Java en el equipo mediante el valor de la variable pid. Notemos que el mandato java –version muestra la versión actual de Java por consola y, puesto que esto no debería ser leído por el usuario final, hemos de redireccionar la salida a nul. Tras esto, y solo en caso de que no haya ninguna versión de Java instalada, el código C++ ejecuta el instalador de la correspondiente JRE (en el caso de nuestro creador de instaladores, dicho instalador corresponde a la versión 6 – Actualización 18). Por último, independientemente de si Java está instalado, el código C++ ejecuta el jar del instalador tras esconder la molesta consola que acompaña a sus programas. Otro aspecto que hubo que corregir está relacionado con el subdirectorio de la carpeta de instalación en el que debían copiarse los archivos. En versiones primitivas del creador de instaladores, los archivos de la instalación no se podían copiar en otro sitio que no fuera el directorio de destino, aunque hubiéramos querido ubicarlos en una subcarpeta de dicho directorio al tratarlos de forma individual (por ejemplo, para hacer un acceso directo a ese archivo en concreto). El error se corrigió añadiendo a la estructura del XML un subelemento más al elemento “origen”, llamado “destino”, en el cual se indica la ruta dentro del directorio de destino en la que se va a copiar el archivo. La aplicación guarda esta ruta en la variable destShorcut, en caso de que exista en el XML (el subelemento “destino” podría omitirse, en cuyo caso el lugar en el que se copia el archivo sería la propia carpeta de instalación). 57 La creación del fichero auto-ejecutable que extrae los archivos de la instalación y la ejecuta requirió varias horas de investigación. En un principio se pensó que bastaba con la creación de un fichero jar que almacenara todos los archivos del programa que se debían instalar y que ejecutara el instalador que tuviera dentro (lo cual se habría podido conseguir con un simple doble clic, gracias a los ficheros de manifiesto). No obstante, se reconsideró tal idea, debido a que es posible que el usuario final no tenga ninguna máquina virtual de Java instalada en su máquina, o aunque la tenga, carezca de la noción de lo que es un archivo jar. El archivo auto-ejecutable se consiguió gracias al programa 7-Zip, ya que permite crearlo desde la línea de comandos. Para construirlo, es necesario completar dos pasos: creación del fichero comprimido con los archivos requeridos durante la instalación y creación del archivo auto-ejecutable. Para este segundo paso, además de conocer la sintaxis específica del programa, es necesario disponer en la carpeta de la aplicación de dos archivos más, sin contar el fichero de compresión creado en el primer paso: el 7zS.sfx y el config.txt. Éste último fichero de texto es muy importante, ya que con él se especifica, entre otras cosas, el archivo que se debe ejecutar nada más descomprimir el fichero de extensión .7z. Será el propio programa 7-Zip el que se encargue de gestionar la eliminación de los ficheros extraídos una vez se hayan utilizado tras la descompresión. El continuo tratamiento con cadenas de texto indujo la confección de dos métodos Java que se encargan de modificar adecuadamente dichas cadenas con el fin de que la aplicación funcione sin errores. Estos métodos son nombreFichero y cambiarBarra. El primero recibe una ruta determinada y devuelve el nombre del fichero al que hace referencia; este nombre coincidirá con el token que se encuentra en último lugar, tras la última doble barra de la cadena inicial (\\). El segundo se encarga de cambiar cualquier doble barra \\ que le llega en la cadena introducida como parámetro por una barra simple (/), y es útil para ejecutar el mandato específico que invoca al programa 7-Zip. En cuanto a la interfaz de usuario, hay bastantes aspectos a destacar de su implementación. Uno de ellos es la obtención de todos los paquetes disponibles para presentarlos ante el usuario final. Hay que tener en cuenta que los paquetes se pueden repetir tantas veces como quiera el usuario creador y que pueden existir archivos que no están asociados a ningún paquete. Esto se traduce en que nuestro código se tendrá que encargar de copiar en el archivo properties como claves solo aquellos paquetes que no se hayan copiado ya en este archivo, sin incluir en él ningún valor nulo (pues esa es la representación de los archivos que no están asociados a ningún paquete en el vector que recoge los nombres de los paquetes). El método que se encarga de esta labor es generarInstallConfig, perteneciente a la clase Construct. Otro aspecto a considerar con respecto a la interfaz es la forma de determinar qué paquetes se instalarán finalmente y cuáles no. Para ello, contamos con que en la clase Instalador disponemos de un vector que recoge el nombre de los paquetes para cada archivo definido (null para el caso de los archivos que no pertenecen a ningún paquete) y otro con valores booleanos que indica para cada archivo si se instala o no. 58 Recordemos que un archivo que no tiene ningún paquete asociado se deberá instalar obligatoriamente, por lo que nuestra estrategia consistirá en suponer inicialmente que todos los archivos se van a instalar (aunque la decisión del usuario creador sea diferente) para después cambiar el valor del vector de booleanos en las componentes correspondientes a los archivos cuyos paquetes no se instalarán por decisión del usuario final. Así, en el momento que se confirma la instalación, la clase InterfazGrafica busca únicamente aquellos paquetes que no se van a instalar y sus nombres son pasados como parámetro al método setInstPaq de la clase Instalador para cambiar a false el valor de aquellas casillas del vector de booleanos que cumplan que su archivo asociado pertenece al paquete introducido como parámetro. Pero sin duda, lo más complejo de resolver con respecto a la interfaz es de qué modo se podrán mostrar en ella los paquetes a instalar; no sólo por los nombres tan diversos que pueden tener, sino sobre todo por la cantidad indefinida de paquetes que se pueden definir. Esta última circunstancia lleva a la necesidad de tener que construir en la interfaz casillas de verificación (checkboxes) para los paquetes de manera dinámica (en tiempo de ejecución) en caso de no declarar un número máximo de ellos, pues a priori no sabemos cuántos se declararán en el fichero XML. Sin embargo, debido al tamaño limitado de la ventana de la interfaz gráfica, creí poco recomendable permitir la declaración de un número ilimitado de paquetes, por lo que finalmente se decidió acotar el número máximo de paquetes a 10, los cuales son suficientes para llevar a cabo con éxito la inmensa mayoría de todas las posibles instalaciones, además de construir y añadir las casillas de verificación a la interfaz de manera estática. Una vez adoptada la decisión de acotar el número de paquetes, la solución pasa por construir 10 métodos que añadan cada uno una casilla a la interfaz y por contar cuántos paquetes hay exactamente de verdad. De esto último se encarga el método contarPaquetes, el cual además añade el nombre de estos paquetes a un vector para facilitar su posterior gestión. Para determinar el número de paquetes, este método cuenta en realidad el número de claves del archivo de configuración install.properties diferentes a las que siempre aparecerán, a saber: “Ruta”, “Inicio”, “Escritorio”, “Todos” y “Programas”. Después de todo esto, será fácil determinar los métodos getCheck que serán invocados para añadir las correspondientes casillas de verificación a la interfaz del usuario final (tantos como paquetes hayan sido declarados). 59 4.5. Pruebas En este proyecto, debido a sus peculiaridades y a su modo de desarrollo, no ha habido una única fase de pruebas, sino que éstas han tenido lugar cada vez que se ha diseñado una solución para cada nuevo requisito a implementar. En este apartado resumiremos los resultados de las pruebas que más significativas resultaron, así como las modificaciones que causaron en el código. 4.5.1. Pruebas de comprobación de la funcionalidad Estas pruebas se basaron simplemente en determinados cambios que se introdujeron en el fichero XML de configuración; los cambios que pueda introducir el usuario final con respecto a la configuración inicial son equivalentes a los que pueda introducir el usuario creador del instalador. Antes de esto, hay que indicar que el resto de pruebas realizadas tuvieron un resultado satisfactorio. Fueron pruebas para comprobar que… El nombre que iba a tener el instalador era el deseado. Para ello, se modificó el atributo “nombre” del elemento “instalador” del fichero XML. Resultado: el archivo auto-ejecutable que hace las veces de instalador tenía como nombre el especificado, con la extensión .exe. Los archivos o directorios cuyas rutas se indicaban en el subelemento “archivo” del XML y que formaban parte de la instalación se copiaban en los lugares previstos. Los accesos directos asociados a algunos de estos archivos se creaban en los lugares especificados en los atributos “programas”, “escritorio”, “inicio”, “menuInicio” y “aplicaciones” del elemento “origen” del XML, así como que estos accesos directos iban acompañados por el icono cuya ruta quedaba especificada en el subelemento “icono” del elemento “origen”, siempre que se decidiera que el acceso directo estuviera acompañado por algún icono. En caso de que se quisiera copiar un archivo que tuviera necesariamente que estar dentro de alguna carpeta que se hubiera creado en el directorio de la instalación, el archivo se copiaba en la ruta adecuada, la cual quedaba completamente determinada por el subelemento “destino” del elemento “origen” del XML. La carpeta de instalación quedaba ubicada en la ruta que aparecía en el subelemento “destino” del elemento “lugaresInstalacion”, y que esta carpeta tenía el nombre indicado en el subelemento “programas” del mismo elemento. Se creaba un nuevo grupo de programas, con el mismo nombre que la carpeta de instalación, si el atributo “incluir” del elemento “programas” tenía el valor “Yes”, y que no se creaba en caso contrario. 60 Se modificaba adecuadamente el registro de Windows de acuerdo a los valores de los atributos de los elementos “instalacion” y “desinstalacion” y al texto presente en los subelementos del elemento “desinstalación” en caso de que el valor del atributo “modificar” del elemento “registro” fuera “Yes”, y que no se producían cambios en el registro en caso contrario. El registro de Windows también se modificaba correctamente, considerando la información almacenada en el elemento “customize”, en caso de que existiera en el fichero XML; es decir, que se cambiaba la ruta del registro indicada en el atributo “ruta”, que el tipo del valor cambiado era el especificado en el atributo “tipo” (REG_DWORD, en caso de que el valor de este atributo fuese la cadena vacía), que la clave del registro modificada era la misma que el valor del atributo “clave” y que el nuevo valor de esa clave coincidía con el del atributo “valor”. La instalación era válida para todos los usuarios del equipo en caso de que el atributo “todos” del elemento “usuarios” valiera “Yes”, mientras que solo era válida para el usuario actual en caso contrario. El icono que acompañaba al acceso directo del desinstalador se encontraba en la ruta establecida por el subelemento “icono” del elemento “desinstalador” en caso de que éste tuviera un valor distinto de la cadena vacía, y que el acceso directo carecía de icono en otro caso. Se ejecutaban los archivos e/o instaladores indicados en el elemento “ejecutable”, en caso de que fuese necesaria su puesta en marcha tras completarse la instalación, así como que su ejecución tenía lugar gracias al programa especificado en el atributo “prog” del mismo elemento (que contendría a la cadena vacía en caso de que en realidad no fuera preciso ningún programa). La aplicación soportaba que hubiera varios elementos del XML del mismo tipo (como es el caso de los elementos “origen”, “customize” y “ejecutable”) y que funcionaba correctamente atendiendo a la información residente en cada uno de ellos. En pruebas realizadas en equipos diferentes al mío, la aplicación funcionaba bien, de modo que se actualizaban adecuadamente las variables del sistema PATH y CLASSPATH y se ejecutaba la instalación de la JRE de Java en caso de no disponer de ella. Como hemos indicado antes, la ejecución de ciertas pruebas dieron lugar a la detección de algunos errores existentes en la aplicación que tratábamos de desarrollar en este proyecto. A continuación, detallaremos tanto los fallos encontrados como la solución para corregirlos en ese momento. 61 Prácticamente cada vez que se tenía la necesidad de que un fichero escribiera una determinada ruta en otro fichero, o con menos frecuencia cuando el método principal tenía que leer alguna ruta del fichero XML de configuración, al ejecutar el instalador aparecía un error (en el primer caso) o ni siquiera se llegaban a compilar correctamente los archivos Instalador.java o Desinstalador.java (en el segundo caso). La causa del error era el tratamiento especial que en Java se le tiene que dar al símbolo de la contrabarra (\), ya que se trata de un carácter especial, lo cual hacía que no sirviera introducir las rutas en su formato normal (en las que los directorios aparecen separados por una sola barra invertida). La solución que se adoptó consistió en añadir contrabarras adicionales a cada una de las rutas que se escribían en los ficheros creados por la aplicación, una por cada fichero en el que se tuviera que escribir dicha ruta. Por ejemplo, si una ruta tenía que escribirse en dos ficheros durante el proceso de compilación o ejecución de la aplicación, era obligatorio escribir hasta 4 contrabarras entre directorio y directorio con el fin de evitar tratar a este símbolo como un carácter especial. Este problema no solo tuvo lugar con la barra invertida, sino también con cualquier carácter especial en Java (las comillas, etcétera). Para estos casos, la solución fue equivalente a la anterior. Otro problema surgió con los espacios en blanco. En determinadas ocasiones, era preciso introducir nombres de directorios o rutas completas como parámetros de programas ejecutados desde la línea de comandos (por ejemplo, el Shortcut.exe). Si estos nombres o rutas tenían espacios en blanco, el programa fallaba, pues entonces deberían haber estado encerrados entre comillas. Es evidente que dichos fallos no fueron detectados hasta que esta clase de programas no se incorporaron al proceso de desarrollo, aunque se corrigieron de forma sencilla encerrando entre comillas dichos nombres y rutas en los archivos Java correspondientes (añadiendo las contrabarras que fuesen necesarias, según el punto anterior, pues las comillas son tratadas como caracteres especiales). En el fichero XML de configuración existen algunos elementos y atributos que no se pueden omitir. Si así fuera, ocurriría un error en tiempo de ejecución dentro de las clases Instalador y Desinstalador, pues nuestra aplicación tratará bajo cualquier circunstancia de leer sus valores, de forma que si no existiesen se produciría una excepción. Los encargados de que el fichero XML de configuración esté definido de modo correcto con el fin de preservar errores de este tipo en nuestra aplicación es o bien el fichero DTD o el fichero XML-Schema, ya que ambos están asociados al XML con ese fin. Pero, ¿qué ocurriría si esos ficheros estuvieran mal diseñados? ¿Qué pasaría si en ellos se declararan atributos opcionales que en realidad debieran ser obligatorios? La respuesta es que el usuario creador de la instalación podría dejar sin incluir estos elementos o atributos en el XML sin que los ficheros DTD o XMLSchema advirtieran nada, y aún así producirse excepciones y errores en nuestra aplicación, algo no deseable. 62 Las pruebas que detectaron estos errores consistieron en omitir en el XML parte de los atributos que, en un principio, eran considerados por el DTD y el XML-Schema como opcionales. La solución consistió en declarar como obligatorios aquellos atributos que ocasionaban errores o excepciones por su omisión. Otro error se producía al no declarar ningún icono para el acceso directo del desinstalador. La forma de especificar esto en el fichero XML es dejar vacío el subelemento “icono” del elemento “desinstalador”. No obstante, cuando se hacía esto, se producía una excepción en tiempo de ejecución que, aún así, no impedía que la aplicación se comportara de acuerdo a lo especificado (pues finalmente se construía el acceso directo). Lo que producía este error, cuyas causas no fueron fáciles de deducir, era en realidad un error de programación que describiremos en las siguientes líneas. El atributo iconDesinst de la clase Construct.java recoge la ruta relativa en la que se encuentra el icono que acompaña al acceso directo del jar del desinstalador, de forma que, para detectar si se ha declarado algún icono que represente al acceso directo del desinstalador, es necesario comparar su valor con la cadena vacía (pues el subelemento “icono” del elemento “desinstalador” es obligatorio en el fichero XML): tal icono existirá si su valor es distinto de la cadena vacía. Pues bien, en el código realmente se comparaba su valor con el de null, y puesto que null es distinto que la cadena vacía, la aplicación intentaba crear el acceso directo (con el consiguiente error). Una vez corregida la errata, todo funcionó del modo apropiado. Por último, apuntaremos en las siguientes líneas un comportamiento inesperado de nuestra aplicación que tuvo lugar al probar la creación de la instalación de un programa desarrollado por Jónathan Heras, miembro del Departamento de Matemáticas y Computación de la Universidad de La Rioja. Este comportamiento consistía en que, durante unos segundos después de completarse la instalación del programa en cuestión, aparecían en el escritorio (lugar en el que se precisaba la creación de un acceso directo a un archivo del programa) hasta 3 accesos directos iguales. No obstante, tras esos instantes, desaparecían los accesos directos sobrantes. El resto de requisitos se cumplían en este caso. Hasta la fecha no se ha encontrado una explicación a este fenómeno. Sin embargo, hay que apuntar que sólo se ha producido en el ordenador del miembro colaborador (en el que, por cierto, ya estaba previamente instalado el programa, algo que jamás ocurriría en una situación normal). No solo se han realizado pruebas con esta aplicación (fKenzo). También se ha trabajado con el programa TutorMates de Addlink Research, S.L. Recordemos que es posible que nuestro programa sea el encargado de construir el instalador de esta aplicación en un futuro. 63 4.5.2. Pruebas de la interfaz de usuario Las pruebas para comprobar el correcto funcionamiento de la interfaz de usuario se centraron en comprobar que la información introducida en ella se tenía en cuenta a la hora de realizarse el proceso de la instalación, en que era capaz de mostrar la configuración elegida por defecto por el usuario creador y en que al desinstalador se le proporcionaba realmente la información adecuada para revertir los cambios producidos por el instalador. La mayor parte de estas pruebas resultaron satisfactorias; en las siguientes líneas explicaremos los problemas que surgieron con las restantes y las soluciones que se adoptaron para solucionarlos. Las contrabarras volvieron a plantear dificultades en la implementación de la interfaz. En esta ocasión, provocaban que el archivo destruir.bat necesario para borrar el directorio de instalación no actuara del modo correcto. En concreto, lo que ocurría consistía en que se escribían en este archivo rutas en las cuales parte de algunos de sus directorios se separaban mediante doble barra, cuando debían escribirse con barra simple para que los mandatos funcionaran bien. Esto se debía a que, por la necesidad de escribir esas mismas rutas en otros archivos, se requería que estuviesen separados sus directorios por la doble contrabarra. La solución que se adoptó fue recoger en una variable la ruta con sus directorios separados por una sola contrabarra y escribir esta representación de la ruta en el archivo destruir.bat. Dicha representación podía conseguirse de forma inmediata leyendo la ruta directamente del fichero de configuración install.properties. El fichero properties también ocasionó varias dificultades. Una de ellas era la obtención de sus claves para mostrarlas debidamente en la interfaz de usuario. Resulta que al leer una clave formada por varias palabras de un archivo de propiedades mediante el método keys(), se devuelve únicamente la primera palabra de la clave (ignorándose el resto). Esto hacía que el nombre de los paquetes no se mostrara de forma correcta en la interfaz y que se perdiera información en el proceso de instalación de los paquetes. La solución consistió en escribir el nombre de los paquetes en el archivo de propiedades separando las palabras que lo conformaban por guiones bajos ‘_’ en lugar de por espacios en blanco. Después, el método cambiarBarraBaja de la clase InterfazGrafica se encargaría de hacer los cambios necesarios con el fin de que los nombres de los paquetes se mostraran separados por espacios en blanco. Esa es la razón por la cual nunca deberíamos nombrar a un paquete con barras bajas. 64 Pero el contratiempo más importante con respecto al archivo de propiedades fue el hecho de que, por alguna razón, se añadía al jar del desinstalador antes de que fuera modificado con los cambios producidos por el usuario final tras ejecutar el instalador, haciendo que el desinstalador nunca obtuviera los parámetros correctos para revertir los cambios en el sistema. Tras algunas pruebas, se comprobó que este error no sucedía si los datos del archivo de configuración se guardaban en otro archivo distinto al inicial, el install.properties. A este nuevo archivo se le denominó desinstall.properties, y es realmente este fichero de propiedades el que va a usar siempre el desinstalador para obtener los datos de la instalación y llevar a cabo la desinstalación de manera correcta. Por último, apuntaremos que al ejecutarse la interfaz gráfica aparecía siempre al fondo y en segundo plano una consola vacía que permanecía abierta durante todo el proceso de instalación, hasta el momento en el que ésta terminaba. La consola aparecía como consecuencia de la ejecución del archivo Setup.exe, escrito en C++, aunque en un principio se pensara que el responsable de que se mostrara era Java. Puesto que no es deseable la aparición de tan molesta e innecesaria consola, se tomó la decisión de tratar de ocultarla después de la posible instalación de la JRE de Java (de la cual también se encarga el programa Setup.exe), pues la aplicación sí que usa la ventana para informar al usuario durante este proceso. El código en C++ que nos proporcionó la solución es el siguiente: HWND hide; AllocConsole (); hide = FindWindowA("ConsoleWindowClass",NULL); ShowWindow (hide, 0); Para la ejecución de este código, es necesario incluir el paquete windows.h de C++. 65 4.6. Gestión del proyecto Tras la finalización del proyecto, podemos decir que se han cumplido los plazos previstos para su entrega, pero no la realización del número de horas estimado para su elaboración. Es decir, a pesar de que finalmente no ha habido ningún retraso, de forma paradójica tampoco se ha invertido el tiempo total previsto para la realización del PFC (se ha pasado de dedicarle 540 horas a unas 305; esto es, un poco más de la mitad). La explicación a este hecho radica en la planificación que se ha seguido durante el desarrollo de nuestra aplicación, consistente en dos pasos sucesivamente repetidos: estudio de una nueva funcionalidad del creador de instaladores IzPack e implementación de la misma. Así, puesto que las horas invertidas no alcanzan a las planificadas inicialmente, se ha obtenido una aplicación cuyas prestaciones son menores de lo que se esperaba, pues no satisface todos los requisitos que cumple IzPack (porque no ha dado tiempo a estudiarlos e implementarlos todos). En resumen, se ha completado la labor que se ha podido realizar en el tiempo estipulado al comienzo del proyecto, hasta lo que ha dado tiempo a hacer. Esto no quiere decir que el proyecto sea deficiente en algún sentido. Las funcionalidades que se han implementado representan el grueso de la aplicación, sus entresijos, siendo por tanto la parte más difícil del desarrollo. Esto significa que lo no implementado se refiere a detalles de menos importancia en referencia a la programación, tales como: Pantallas de presentación y cierre de la instalación. Incorporación de una barra de progreso en los procesos de instalación y desinstalación que informe al usuario del grado de avance en el que se encuentran. Posibilidad de cancelar la instalación o la desinstalación mientras se están llevando a cabo. Incorporación de una interfaz que sirva para mostrar información relativa a la aplicación que se desea instalar. Presentación de los paquetes de archivos que se van a instalar seguro. Descripción de los paquetes de archivos que se pueden instalar. Cálculo del espacio disponible en el disco duro. Lo relativo a la barra de progreso y la cancelación de la instalación o desinstalación en el transcurso de su ejecución puede resolverse mediante la creación de hilos de ejecución (llamados comúnmente threads) en Java, y requeriría un poco de estudio por mi parte para implementarlo (conozco el concepto de hilo de ejecución, pero no la forma de programarlo en Java). Lo mismo puede decirse con respecto al cálculo del espacio en disco, pero una vez estudiado cómo se puede obtener este dato, sería muy fácil mostrarlo. Lo demás no supondría ningún esfuerzo adicional. En consecuencia, el esfuerzo que debería realizar para incorporar al proyecto estas funcionalidades es netamente menor en comparación al invertido con las implementadas. 66 La razón por la que se han invertido un poco más de la mitad de las horas previstas al inicio en la realización del PFC es simple: su elaboración ha tenido que ser compaginada durante todo el ciclo académico con el último curso de la doble titulación; de ahí que las 3 horas que se pensaban dedicar a esta tarea cada día fuesen demasiadas para lo que se pretendía hacer. Al final, el tiempo real invertido cada semana acabó por no superar las 8 horas, incluyéndose la mayor parte de ellas durante los fines de semana. He de apuntar que, además, sólo he podido disfrutar de una dedicación exclusiva a la realización del PFC durante el último mes, tras la finalización de los exámenes de junio. Por otro lado, otras razones por las que no ha dado tiempo a realizar todo lo previsto pueden ser la falta de experiencia ante un proyecto de tal magnitud y el hecho de usar herramientas desconocidas para mí hasta su comienzo, hándicaps que tuvieron una gran influencia sobre todo al principio, como es natural. Aunque bien es cierto que existía la posibilidad de retrasar la entrega del proyecto a septiembre o incluso al siguiente curso académico para mejorarlo, se acabó desechando tal opción, pues prefería dar prioridad a la continuidad de mi formación académica frente a prolongar más tiempo el PFC. Por otro lado, tanto Julio Rubio como yo consideramos que se han superado con creces los objetivos más básicos del proyecto, siendo ésta la razón más sustancial por la que se decidió presentarlo en el momento actual. 67 4.7. Conclusiones 4.7.1. Concordancia entre resultados y objetivos En líneas generales, los resultados obtenidos satisfacen los objetivos que se determinaron al comienzo del proyecto. El creador de instaladores desarrollado es capaz de ofrecer al usuario un abanico de posibilidades suficientemente amplio como para crear cualquier tipo de instalación con la configuración que más le convenga, pues le permite crear accesos directos en los directorios más utilizados a tal efecto, modificar a su antojo los valores del registro de Windows (facilitando, incluso, el acceso a las rutas del registro que cambian con más frecuencia durante las instalaciones), dar un nombre al instalador, elegir el directorio de instalación, crear automáticamente un nuevo grupo de programas, indicar para qué usuarios será válida la instalación, permitir la ejecución de instaladores de productos externos inmediatamente después de la instalación… Además de estas funcionalidades y debido al uso que hace de la tecnología Java, nuestro creador de instaladores también consigue incorporar una versión de la máquina virtual de Java (JRE) que se instalará en el equipo del usuario que ejecuta la instalación si éste no disponía previamente de ella. Por consiguiente, la aplicación desarrollada en este proyecto supera en este aspecto a ciertos creadores de instaladores (como IzPack), ya que éstos no ofrecen esta posibilidad al usuario a pesar de estar implementados en lenguaje Java. Otro aspecto que consigue mejorar con respecto a IzPack (o, por lo menos, corregir) está relacionado con la modificación del registro de Windows: IzPack también satisface este requisito, pero con errores en determinadas ocasiones, lo que hace que algunos usuarios de este producto desconfíen de esa funcionalidad. Aunque quizás la forma que utiliza nuestro producto para llevar a cabo tal cometido pueda resultar menos cómoda para el usuario, lo que sí se ha comprobado es que es fiable y libre de errores. 4.7.2. Lecciones aprendidas Este proyecto me ha servido, sobre todo, para aumentar mis capacidades de trabajo de investigación. Se trata de un proyecto eminentemente tecnológico, basado en la realización de un producto completamente original y novedoso que, aunque en el fondo intente emular a un software ya existente y conocido, ha nacido desde el ingenio y la búsqueda de ideas que resolvieran las dificultades de implementación a las que me he ido enfrentando. 68 En cuanto a la planificación, este proyecto también es muy válido para apreciar en su verdadera medida las ventajas que proporcionan las metodologías de desarrollo más valoradas en la Ingeniería del Software. En este caso, debido a la naturaleza del proyecto, no ha quedado otro remedio que abordar el desarrollo de la aplicación sin haber especificado de antemano todas las funcionalidades que era preciso implementar, lo cual resultó muchas veces incómodo y arriesgado, pues a la hora de implementar nuevos requisitos era muy probable que hubiera que hacer cambios adicionales en el código, aumentando la probabilidad de que se produjeran errores o de que no los encontráramos. Además, estos cambios en el código suponían un esfuerzo extra difícil de medir a priori y que causaban demasiada inseguridad en el programador, el cual tenía que disponer de la valentía y el coraje suficientes como para modificar el código escrito asumiendo los anteriores riesgos. Todas estas dificultades no habrían tenido lugar si la metodología usada hubiera especificado todos los requisitos desde el principio. Otro motivo de aprendizaje fue el hecho de trabajar con herramientas y programas de software desconocidos para mí al comienzo del proyecto. Esto me permitió obtener una mayor confianza de cara al futuro a la hora de manipular y manejar software de manera autodidacta. Esta capacidad es importante, pues es posible que me vea obligado a aprender a utilizar nuevos programas y herramientas por mí mismo y sin la ayuda de nadie que me instruya en determinadas situaciones. Además, algunas de las herramientas a las que me refiero son frecuentemente utilizadas en el ámbito de la programación, hasta el punto que las llegué a estudiar durante el último curso de la carrera (como la modificación del PATH y el CLASSPATH o el uso de JDom), por lo que la experiencia ha podido resultar muy útil para mí. 4.7.3. Líneas de ampliación posibles Puesto que este proyecto se basa en la emulación de un creador de instaladores existente, es probable que no se hayan implementado algunas de las funcionalidades que proporciona. Otra posible línea de ampliación para este proyecto es la incorporación de un soporte multilingüe, de modo que cada instalación pueda mostrar interfaces gráficas en diferentes idiomas, así como la implementación de un soporte multiplataforma que permita configurar instalaciones también en otros sistemas operativos distintos de Windows, como Linux o Macintosh. La consecución de estas mejoras estarían seguramente basadas en el diseño de una base de datos que recogiera cada uno de los mensajes mostrados en la interfaz en los diferentes idiomas disponibles y cada uno de los mandatos utilizados traducidos al lenguaje de programación propio de los diferentes sistemas operativos considerados. Por último, otra línea de mejora podría centrarse en la construcción de una interfaz para el usuario creador del instalador, de forma que ya no tendría que verse obligado a construir un fichero XML de configuración para realizar su tarea. De hecho, realmente se da la existencia de ciertos creadores de instaladores que incorporan tal interfaz. Por supuesto, cabe recordar que el proyecto puede mejorarse implementando las funcionalidades que proporciona IzPack y que finalmente no se consideraron por falta de tiempo. En concreto, estas funcionalidades han quedado recogidas en el apartado 4.6, Gestión del proyecto. 69 4.8. Bibliografía 1) Juan Diego Gutiérrez Gallardo: Manual imprescindible de XML. Anaya Multimedia, 2005. 2) Ejemplos de instaladores creados mediante IzPack: http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=IzPack. 3) Página oficial de IzPack: http://izpack.org. 4) Funcionamiento de CLASSPATH y jar: http://www.chuidiang.com/java/classpath/classpath.php. 5) Crear un archivo jar ejecutable: http://login.osirislms.com/index.php?modname=foro&op=message&idThread=28. 6) Página oficial de JDom: http://www.jdom.org. 7) Ejemplos de uso de JDom: http://www.javahispano.org/contenidos/archivo/48/jdom1.pdf. 8) Determinar el usuario actual del sistema: http://stackoverflow.com/questions/473446/java-current-machine-name-andlogged-in-user. 9) Página para la descarga del programa Shortcut.exe: http://optimumx.com/download/#Shortcut. 10) Información del registro de Windows: http://support.microsoft.com/kb/256986/es. 11) Página oficial de 7-Zip: http://www.7-zip.org. 12) Crear un archivo auto-extraíble mediante 7-Zip: http://prudentialscatterbrain.hp.infoseek.co.jp/7z4.20_MANUAL/switches/sfx.htm, http://it.megocollector.com/?p=16. 13) Especificación de la API de Java: http://download.oracle.com/docs/cd/E17476_01/javase/1.3/docs/api/overviewsummary.html 70 4.9. Anexos 4.9.1. ANEXO I: Manual de instrucciones del usuario creador INSTRUCCIONES DE USO: 1º) En la misma carpeta que se proporciona (la que contiene el Make.bat) se añaden los archivos que se utilizarán durante la instalación: iconos, carpetas que se copiarán, programas o instalaciones externos que se deben ejecutar en el transcurso de la instalación... 2º) También en la misma carpeta, debe crearse un archivo XML de nombre Instalador.xml. La estructura que debe tener dicho archivo está especificada en Instalador.dtd y en Instalador.xsd. A continuación se indica el significado de cada atributo y elemento: • Elemento instalador: raíz del documento. Atributos: nombre: lleva el nombre que tendrá el instalador. • Elemento fuentes: puede contener varios elementos "origen". • Elemento origen: cada uno contiene un fichero que se copiará en el destino. Atributos: programas: indicar "Yes" si se desea instalar el fichero en el grupo de programas de la aplicación; "No", en caso contrario. escritorio: indicar "Yes" si se desea hacer un acceso directo en el escritorio; "No", en caso contrario. inicio: indicar "Yes" si se desea que el programa se cargue al arrancar Windows; "No", en caso contrario. menuInicio: indicar "Yes" si se desea hacer un acceso directo en la carpeta de programas del menú Inicio; "No", en caso contrario. aplicaciones: indicar "Yes" si se desea hacer un acceso directo en la carpeta de aplicaciones del menú Inicio; "No", en caso contrario. Subelementos: paquete: conjunto de archivos que se instalan como un todo: si se decide que un archivo de un paquete debe ser instalado, el resto de archivos de ese paquete también se instalarán. Dos archivos diferentes pertenecen al mismo paquete si el valor de este elemento es el mismo en ambos casos. Incluye el atributo obligatorio "defecto", que puede tomar como valor "Yes" o "No": "Yes", si se desea instalar por defecto este paquete; "No", en caso contrario. El número máximo de paquetes soportados es 10. El nombre de los paquetes nunca deberá contener ninguna barra baja ('_'). 71 archivo: ruta del archivo (dentro de la carpeta del creador de instaladores) que se copiará en la carpeta de destino. Los subdirectorios se separan mediante \\ (esto será válido para cualquier ruta de aquí en adelante en este documento). icono: ruta del icono (si existiera) que se asociará al archivo anterior (en caso de que admitiera un acceso directo). Si un archivo para el que se va a crear un acceso directo no tiene ningún icono asociado, este elemento puede dejarse vacío u omitirse. destino: útil solamente si se desea copiar un archivo dentro de una carpeta que se instalará en el directorio de destino. Por ejemplo, si se desea copiar la carpeta <miCarpeta> en el destino de modo que esta carpeta contiene una subcarpeta llamada <subCarpeta> que a su vez contiene el archivo <miapp> y deseamos copiar este último archivo dentro de la anterior subcarpeta, hemos de escribir en "destino" lo siguiente: <miCarpeta>\\<subCarpeta>. Si no consideramos el subdirectorio <subCarpeta> en el anterior ejemplo, bastaría con escribir <miCarpeta>. Por último, si el archivo <miapp> no se encuentra dentro de ningún directorio, el subelemento "destino" debe omitirse (o dejarse en blanco). • Elemento lugaresInstalacion: contiene información acerca de los lugares en los que se instalará la aplicación. No contiene texto de ningún tipo: solo subelementos. • Elemento destino: contiene la ruta de la carpeta de instalación. • Elemento programas: contiene el nombre de la carpeta de instalación. Atributos: incluir: "Yes" si se desea crear un grupo de programas dentro del menú Inicio. El nombre del grupo sería el mismo que se indica en el elemento "programas" (es decir, el de la carpeta de instalación). "No", en caso contrario. • Elemento registro: contiene solo subelementos que incorporan la información de modificación del registro de Windows. Atributos: modificar: "Yes" si se desea modificar el registro; "No", en caso contrario. Si se indica "No", se obviará la información que puedan contener los subelementos. • Los elementos instalacion y desinstalacion tienen como atributos las claves de registro de instalación y desinstalación de Windows. Además, “desinstalacion” incluye subelementos en los que se muestran los valores de algunas de esas claves (si son distintos de "Yes" o "No"). • Elemento customize: permite modificar el registro libremente, a gusto del usuario. Atributos: ruta: guarda la ruta del registro que se va a modificar. tipo: tipo de dato del valor que se introducirá en el registro. El tipo por defecto es REG_SZ. clave: guarda la clave de la ruta del registro que se modificará. 72 valor: Cadena que se almacenará en la clave indicada del registro. • Elemento usuarios: indica si la aplicación se instalará para todos los usuarios o solo para el actual. Atributos: todos: valor "Yes", para todos los usuarios; valor "No", sólo para el actual. • Elemento desinstalador: solamente incluye un subelemento. Subelementos: icono: Guarda la ruta del icono que se mostrará con el acceso directo del desinstalador. En caso de no existir tal icono, el elemento debe dejarse vacío. • Elemento ejecutable: incluye la ruta de aquellos programas, ejecutables o instalaciones externos a la instalación de nuestra aplicación que deben ejecutarse durante el transcurso de ésta. Atributos prog: guarda el programa con el que debe abrirse el ejecutable o instalador, en caso de que sea necesario. NOTA: Para asegurar el correcto funcionamiento de la aplicación, es necesario que el documento XML sea completamente acorde a la DTD a la que está asociado; en otro caso, su comportamiento no tendrá por qué ser el esperado. 3º) Se modifica la variable del sistema PATH con la ruta del directorio bin de la JDK de Java que está instalada en su equipo. Por ejemplo, si tiene instalada la versión 1.6.0_17 en el directorio "Java" de "Archivos de Programa", escriba en la línea de comandos: SET PATH=%PATH%;c:\Archivos de programa\Java\jdk1.6.0_17\bin Es necesario que su equipo disponga de la JDK de Java para que funcione esta aplicación. 4º) Se ejecuta Make.bat. El resultado es un ejecutable .exe con el nombre del instalador. Dicho ejecutable se encargará de extraer los archivos de instalación, ejecutar la instalación, modificar el registro de Windows y gestionar la posterior eliminación de los archivos extraídos. También se incluye un desinstalador que eliminará todos los archivos copiados en la carpeta de instalación y los accesos directos, el cual además eliminará las entradas correspondientes del registro. Además, en caso de que el equipo en el que tiene lugar la instalación no tenga instalada ninguna versión de la JRE de Java, se instalará en él la versión 6 – update 18. 73 4.9.2. ANEXO II: Cronología del Proyecto Fin de Carrera 1/10/2009: Busco información sobre algunos creadores de instaladores, centrándome en aquel al que tendré que emular, IzPack. Por ahora, me interesa conocer su funcionalidad, por encima del resto de sus características (4 horas). Por otro lado, comienzo a estudiar por mi cuenta el lenguaje XML (el cual hasta ahora es desconocido para mí), ya que será imprescindible para llevar a cabo el PFC (los creadores de instaladores han de ser configurables precisamente a través de ficheros XML). (5 horas). 8/10/2009: Siguiendo con mi iniciación en XML, me hago con un libro que enseña las nociones más básicas: “XML: Manual imprescindible”, de Juan Diego Gutiérrez Gallardo. Con esto, aprendo la utilidad de XML para guardar y organizar los datos (7 horas). 24/10/2009: Finalizo mi “primer” creador de instaladores, el cual simplemente construye el código necesario para copiar un fichero de texto en cualquier directorio existente. Se trata del creador de instaladores más sencillo que puede haber, pero su filosofía es la misma que utilizará la versión definitiva: generar código fuente en un fichero Java, el cual hará las veces del instalador tras compilarlo y ejecutarlo (en este sencillo caso, dicho instalador se llama “Instalador.java” y se limita a copiar el fichero indicado en la ruta existente especificada). (5 horas). Durante la elaboración de esta primitiva versión del creador de instaladores, me surgieron las primeras dificultades y dudas. Una de ellas fue el modo de compilar el fichero “Instalador.java” (esto es, el instalador en sí) de un modo automático y fácil; por ejemplo, con doble clic. El problema lo resolví mediante la construcción de un archivo ejecutable por lotes (.bat), en el cual se incluían las órdenes necesarias para compilar (mediante javac.exe) y ejecutar (mediante java.exe) el instalador. Otro problema, muy ligado al anterior, era que el sistema no encontraba la ruta del javac.exe, debido a una incorrecta configuración de la variable de entorno CLASSPATH. Tras resolver esto, el fichero .bat se ejecutaba sin presentar más dificultades. Por último, apuntaré que el modo de copiar el fichero en el directorio fue a través de la creación de un búfer de datos, el cual leía una determinada cantidad de bytes del fichero para escribirlos en el fichero de destino (3 horas). 25/10/2009: Consigo que la aplicación lea de un fichero XML tanto el nombre del archivo que se quiere instalar como la ruta de la instalación, así como el nombre que se desea que tenga el instalador. Esto sólo fue posible tras la instalación de JDom en mi equipo, válido para facilitar el acceso a ficheros XML que deben ser leídos por programas en Java. Además, consigo crear desde el programa el .bat referido anteriormente, el cual compila y ejecuta el instalador (5 horas). 74 13/11/2009: Realizo mi primer instalador mediante IzPack. Dicho instalador se encarga de instalar una pequeña aplicación en Java en los directorios que se le dictan. El objetivo de aprender a manejar IzPack se debe a dos razones: conocer con más profundidad la funcionalidad de este programa para aplicarla a mi creador de instaladores y crear el instalador definitivo de TutorMates, si la empresa decidiera que lo haga yo (lo cual supondría una remuneración económica por esta labor). (6 horas). Con el fin de crear la primera instalación en IzPack fue necesario obtener los conocimientos más básicos acerca de los ficheros jar (cómo crearlos y cómo ejecutarlos, por ejemplo), ya que la propia instalación se ejecuta a través de estos ficheros (3 horas). 15/11/2009: Consigo que mi aplicación para crear instaladores construya automáticamente un desinstalador de la aplicación que se pretende instalar, basado en un algoritmo recursivo (con el fin de poder borrar posibles subdirectorios, así como todos los ficheros creados). Del mismo modo, también es capaz de construir un fichero jar en el que se comprimen y empaquetan tanto el instalador como el desinstalador a los que me he referido anteriormente, lo cual permite la ejecución de la aplicación en cualquier ordenador que tenga instalada la máquina virtual de Java. Además, se consiguió que ambos se ejecutaran mediante doble clic gracias a la construcción de los correspondientes ficheros jar ejecutables (acompañados de sus ficheros manifest, que indican dónde encontrar la clase que contiene al método principal). (4 horas). 23/11/2009: El creador de instaladores puede hacer que el instalador copie archivos en el escritorio, así como que instale la aplicación para todos los usuarios o solo para el usuario actual (mediante el uso de ‘System.getProperties(“user.name”)’). (4 horas). 27/11/2009: La aplicación permite crear una carpeta con un determinado nombre tanto en la ruta especificada como en el menú “Programas”, siendo esto último opcional. También es opcional la creación de la copia del archivo de la aplicación en el escritorio (3 horas). 1/12/2009: La aplicación permite instalar varios archivos (no solo uno) tanto en la ruta especificada como en el menú “Programas”, de modo que en el escritorio, además, se pueda instalar una copia del archivo principal de la aplicación (5 horas). 5/12/2009: Finalizo el Documento de Objetivos del Proyecto (DOP), primer documento válido para la memoria del PFC (12 horas). 8/12/2009: El instalador se puede ejecutar mediante un ejecutable .exe. Para ello, fue necesaria la creación de un archivo C++ para compilarlo desde el fichero Java, cuyo código permite la creación del instalador (haciendo lo mismo que hacía el .bat). (4 horas). Además, permite que cualquier fichero de los que se desea instalar pueda aparecer en el escritorio, si así se indica (1 hora). 75 12/12/2009: Las copias de los ficheros en el escritorio o en el menú Programas son sustituidas por accesos directos, lo cual permite ahorrar una gran cantidad de espacio en memoria. Para lograr esto, tuve que investigar acerca de cómo crear en Windows estos accesos directos. Necesité para ello la ayuda de una herramienta, llamada “shortcut.exe” (5 horas de investigación más 6 horas de implementación y pruebas). 21/12/2009: El desinstalador permite la eliminación de todas las carpetas y archivos de la instalación, incluyendo al propio desinstalador. Esto fue posible gracias a la creación de un script que es capaz de borrarse a sí mismo y que además ejecutaba los mandatos necesarios para que las carpetas que no eran eliminadas por el desinstalador fuesen borradas por el propio sistema operativo. El script es creado desde el desinstalador (15 horas de investigación más 3 horas de implementación y pruebas). 25/12/2009: El creador de instaladores permite que todos los archivos que se utilizarán en la instalación (iconos, ficheros jar, etcétera) puedan estar ubicados en cualquier subdirectorio de la carpeta en la que se encuentra (y no necesariamente en la misma carpeta), siempre y cuando esto se indique adecuadamente en el fichero XML del que se leen las características de la instalación (2 horas). 26/12/2009: El instalador también permite crear accesos directos en el menú aplicaciones (todos los programas), en la carpeta Inicio y en el menú Inicio, si así se especifica (2 horas). 10/01/2010: El creador de instaladores permite definir los datos que se modificarán en el registro de Windows, una vez instalada la aplicación, así como borrar las entradas introducidas en el registro al desinstalarla. Las entradas que se añaden y las claves que se modifican son: o HKLM\Software\<Programa> Install_Dir (opcional) o HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\<Programa> DisplayIcon (opcional) DisplayName DisplayVersion (opcional) HelpLink (opcional) InstallLocation NoModify (opcional) NoRepair (opcional) UninstallString URLInfo (opcional) (3 horas de investigación + 6 horas de implementación). 17/01/2010: El registro de Windows puede modificarse a gusto del cliente. Además, el programa mantiene las opciones de modificación del registro por defecto (3 horas). Por otro lado, el creador de instaladores permite copiar directorios enteros en el lugar especificado (1 hora). 76 12/02/2010: El creador de instaladores permite ejecutar archivos externos a la instalación, tales como ficheros de texto (tipo readme) o incluso otros instaladores (de programas que pueden ser necesarios para que el que queremos instalar funcione correctamente). (4 horas). 13/02/2010: El programa añade una nueva funcionalidad con respecto a IzPack: es capaz de proporcionar al usuario final (el que a la sazón instalará la aplicación) un ejecutable en lugar de solamente un archivo jar, de modo que si el usuario final tiene instalada la JRE de Java en su equipo, el .exe ejecuta directamente el jar, y si no, instala antes Java. La versión del JRE de Java que se instala es la 6ª, actualización 18. (3 horas de investigación + 5 horas de implementación y pruebas). 16/02/2010: Nueva mejora a la hora de crear accesos directos: el programa permite crear shortcuts a archivos que se encuentran dentro de directorios, y no solo a archivos que se copian individualmente. Del mismo modo, permite indicar en qué ubicación dentro de la carpeta de instalación se desea copiar el archivo. Esta mejora surgió a raíz de las peticiones de Jónathan Heras como usuario de mi aplicación (3 horas). 23/02/2010: El creador de instaladores genera un único fichero auto-ejecutable que es capaz de descomprimir los archivos que almacena para llevar a cabo la instalación, ejecutar el instalador y gestionar la eliminación de los archivos tras la instalación. Para este fin, se usó el programa 7-zip, que es software open-source (11 horas de investigación + 5 horas de implementación y pruebas). Del mismo modo, se creó un fichero de texto con las instrucciones de uso del creador de instaladores y se reorganizaron algunos archivos dentro de la carpeta de la aplicación (2 horas). 25/02/2010: Se genera un manual de instrucciones en formato de texto que permita conocer al usuario cómo manejar la aplicación, lo que es capaz de hacer y los requisitos necesarios para su correcto funcionamiento (1,5 horas). 5/03/2010: Se realiza la documentación del análisis de requisitos (2 horas). 12/03/2010: Se genera la documentación de los casos de uso, la cual incluye la descripción de cada uno de ellos y el diagrama de casos de uso (4 horas). 16/03/2010: Se documenta la interfaz de usuario, en la que se incluyen momentáneamente algunos prototipos de baja calidad (3 horas). Además, se mejora la aplicación de modo que la carpeta con los archivos de la instalación pueda ubicarse en un directorio nuevo definido por el usuario, y no necesariamente en uno ya existente (1 hora de implementación y pruebas). 19/03/2010: Se modela y representa la interfaz de usuario mediante un diagrama de estados o statechart, de modo que se clarifique su comportamiento y su modo de ejecución (2,5 horas). 77 1/04/2010: Se crea un XML-Schema que representa, de un modo más gráfico del que se podría lograr con un DTD, la estructura que debe tener el fichero XML de configuración (2 horas). 5/04/2010: Se termina de documentar la interfaz del usuario creador. Esta nueva documentación incluye una descripción de la estructura que tiene que poseer el fichero XML para que la aplicación funcione correctamente, las precondiciones y poscondiciones que debe cumplir y una explicación de por qué se descartó la creación de una interfaz gráfica para el usuario creador (3,5 horas). 7/04/2010: Se realiza la documentación del diseño (6 horas). 2/05/2010: Se añade a la documentación del diseño un diagrama de colaboración que representa la interacción entre los archivos que participan durante el proceso de instalación y desinstalación (2,5 horas). 23/06/2010: Se documenta la implementación del proyecto (5 horas). 24/06/2010: Se modifica el Documento de Objetivos del Proyecto, de acuerdo a los acontecimientos que se han ido sucediendo durante los meses que ha durado el proyecto. Básicamente, los cambios introducidos se refieren a la eliminación de la funcionalidad relacionada con el soporte multilingüe, que no se considerará por falta de tiempo. (1 hora). 26/06/2010: Se documentan las pruebas del proyecto (5 horas). Por otro lado, se realizan las últimas pruebas, encaminadas a determinar la correcta funcionalidad de la aplicación, lo cual causa modificaciones tanto en el código como en los ficheros DTD y XML-Schema (3 horas). 27/06/2010: Se redactan la introducción y las conclusiones del proyecto (3 horas). 30/06/2010: Se termina la redacción de la primera versión de la memoria, que incluye toda la documentación realizada anteriormente (12 horas). 7/07/2010: Se implementa la interfaz del usuario creador. Para ello, fue necesario hacer el diseño de la interfaz (8 horas); construir la interfaz en Swing (10 horas); investigar acerca de cómo mostrar un árbol de directorios para que el usuario final pueda elegir la ruta de la carpeta de instalación (3 horas), para ocultar la consola de C++ (3 horas), para centrar en la pantalla la ventana (2 horas) y para incluir una barra de progreso en la interfaz (aunque después no se consiguiera poner en marcha) (5 horas); programar la funcionalidad de la interfaz (16 horas); realizar los cambios pertinentes en el código para crear el archivo de propiedades install.properties (6 horas) y realizar la fase de pruebas (7 horas). 13/07/2010: Se añade a la memoria la documentación de la interfaz del usuario final (17 horas). Además, se revisa la memoria y se realizan los cambios pertinentes en ella, inducidos por la creación de la interfaz (15 horas). 15/07/2010: Se prepara la presentación del PFC (6 horas). 78