opensheet - Grupo ARCO - Universidad de Castilla-La Mancha
opensheet - Grupo ARCO - Universidad de Castilla-La Mancha opensheet - Grupo ARCO - Universidad de Castilla-La Mancha
OPENSHEET: LIBRERÍA MULTIPLATAFORMA PARA PROCESAMIENTO AUTOMÁTICO DE HOJAS DE CÁLCULO
- Page 3: UNIVERSIDAD DE CASTILLA-LA MANCHA E
- Page 7: Carlos Ruiz Ruiz Ciudad Real - Spai
- Page 11: Resumen Las hojas de cálculo graci
- Page 15: Agradecimientos Por fin ha llegado
- Page 18 and 19: 2.2.9. Java Excel API . . . . . . .
- Page 20 and 21: 6.2. Posibles mejoras y ampliacione
- Page 23: Índice de cuadros 2.1. Comparativa
- Page 27 and 28: Índice de listados 2.1. Cómo carg
- Page 29: A.28.Ejemplo de fichero de datos .
- Page 33 and 34: Capítulo 1 Introducción LAs aplic
- Page 35: 1. INTRODUCCIÓN 3 uno de los capí
- Page 38 and 39: 6 2. ANTECEDENTES Hoja de cálculo
- Page 40 and 41: 8 2. ANTECEDENTES Actividad del pro
- Page 42 and 43: 10 2. ANTECEDENTES potente. El inco
- Page 44 and 45: 12 2. ANTECEDENTES En realidad se s
- Page 46 and 47: 14 2. ANTECEDENTES String sConnect
- Page 48 and 49: 16 2. ANTECEDENTES XCell xCell = xS
- Page 50 and 51: 18 2. ANTECEDENTES HSSFWorkbook wb
OPENSHEET: LIBRERÍA MULTIPLATAFORMA PARA PROCESAMIENTO<br />
AUTOMÁTICO DE HOJAS DE CÁLCULO
UNIVERSIDAD DE CASTILLA-LA MANCHA<br />
ESCUELA SUPERIOR DE INFORMÁTICA<br />
INGENIERÍA<br />
EN INFORMÁTICA<br />
PROYECTO FIN DE CARRERA<br />
OpenSheet: Librería multiplataforma para procesamiento<br />
automático <strong>de</strong> hojas <strong>de</strong> cálculo<br />
Carlos Ruiz Ruiz<br />
Junio, 2011
UNIVERSIDAD DE CASTILLA-LA MANCHA<br />
ESCUELA SUPERIOR DE INFORMÁTICA<br />
Departamento <strong>de</strong> Tecnologías y Sistemas <strong>de</strong> Información<br />
PROYECTO FIN DE CARRERA<br />
OpenSheet: Librería multiplataforma para procesamiento<br />
automático <strong>de</strong> hojas <strong>de</strong> cálculo<br />
Autor: D. Carlos Ruiz Ruiz<br />
Director: Dr. David Villa Alises<br />
Junio, 2011
Carlos Ruiz Ruiz<br />
Ciudad Real – Spain<br />
E-mail: Carlos2res@gmail<br />
Web site: http://arco.esi.uclm.es/<br />
c○ 2011 Carlos Ruiz Ruiz<br />
Permission is granted to copy, distribute and/or modify this document un<strong>de</strong>r the terms of the GNU<br />
Free Documentation License, Version 1.3 or any later version published by the Free Software<br />
Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy<br />
of the license is inclu<strong>de</strong>d in the section entitled "GNU Free Documentation License".<br />
Se permite la copia, distribución y/o modificación <strong>de</strong> este documento bajo los términos <strong>de</strong> la<br />
Licencia <strong>de</strong> Documentación Libre GNU, versión 1.3 o cualquier versión posterior publicada por<br />
la Free Software Foundation; sin secciones invariantes. Una copia <strong>de</strong> esta licencia esta incluida en<br />
el apéndice titulado «GNU Free Documentation License».<br />
Muchos <strong>de</strong> los nombres usados por las compañías para diferenciar sus productos y servicios son<br />
reclamados como marcas registradas. Allí don<strong>de</strong> estos nombres aparezcan en este documento, y<br />
cuando el autor haya sido informado <strong>de</strong> esas marcas registradas, los nombres estarán escritos en<br />
mayúsculas o como nombres propios.
TRIBUNAL:<br />
Presi<strong>de</strong>nte:<br />
Vocal 1:<br />
Vocal 2:<br />
Secretario:<br />
FECHA DE DEFENSA:<br />
CALIFICACIÓN:<br />
PRESIDENTE VOCAL 1 VOCAL 2 SECRETARIO<br />
Fdo.: Fdo.: Fdo.: Fdo.:
Resumen<br />
<strong>La</strong>s hojas <strong>de</strong> cálculo gracias a su gran versatilidad, por su gran cantidad <strong>de</strong> funciones, a<br />
su potencia <strong>de</strong> cálculo, que permite automatizar operaciones a través <strong>de</strong> fórmulas, y a su<br />
gran sencillez <strong>de</strong> uso, han hecho que se conviertan para muchas empresas y organizaciones<br />
en las herramientas utilizadas para realizar cálculos financieros, guardar informes, gráficos<br />
estadísticos, clasificación <strong>de</strong> datos, etc. Convirtiéndose los documentos <strong>de</strong> hojas <strong>de</strong> cálculo<br />
en una fuente importante <strong>de</strong> datos.<br />
Por tanto son muchas las organizaciones que cuentan con un gran número <strong>de</strong> hojas <strong>de</strong><br />
cálculo que contienen a su vez gran cantidad <strong>de</strong> datos, por lo que sería <strong>de</strong>seable el po<strong>de</strong>r contar<br />
con una herramienta que permita la extracción e inserción <strong>de</strong> datos en hojas <strong>de</strong> cálculo <strong>de</strong><br />
manera automática. Permitiendo así utilizar en otras aplicaciones los datos almacenados en<br />
hojas <strong>de</strong> cálculo, a través <strong>de</strong> la extracción <strong>de</strong> datos; y viceversa, utilizar los datos disponibles<br />
en otras aplicaciones en las hojas <strong>de</strong> cálculo a través <strong>de</strong> la inserción <strong>de</strong> datos.<br />
En este marco se plantea el diseño <strong>de</strong> OpenSheet, un proyecto cuyo objetivo principal es<br />
la extracción e inserción <strong>de</strong> datos en hojas <strong>de</strong> cálculo <strong>de</strong> manera automática y sencilla, soportando<br />
los principales formatos <strong>de</strong> los productos Microsoft Excel y OpenOffice.org Calc.<br />
IX
A Natalia y a mis padres
Agra<strong>de</strong>cimientos<br />
Por fin ha llegado este momento <strong>de</strong>l camino, en el que hay que agra<strong>de</strong>cer a todas aquellas<br />
personas que me han apoyado en algún momento para que lograra terminar el proyecto fin<br />
<strong>de</strong> carrera, a todos ellos gracias.<br />
Primero, quiero dar las gracias a Natalia, mi compañera en este viaje que es la vida, por<br />
darle sentido y por querer compartirla conmigo. Gracias por todo el apoyo que me ha dado<br />
para lograr este objetivo y sobre todo por su paciencia. Espero a partir <strong>de</strong> ahora po<strong>de</strong>r recuperar<br />
todo el tiempo perdido para compensar mi ausencia en esta etapa tan importante para<br />
ambos.<br />
Después, quiero dar las gracias a mis padres que me han enseñado el valor <strong>de</strong> las cosas. A<br />
mi madre por ser siempre un apoyo incondicional para mí, y a mi padre que <strong>de</strong>seaba po<strong>de</strong>r<br />
ver alguna vez esta memoria escrita.<br />
Gracias a Juani, Carmelo y a Mario por darme ánimos constantemente.<br />
Gracias a mis amigos por apoyarme y animarme. En especial, quiero agra<strong>de</strong>cer a Ángel y<br />
a Jose Ántonio todas esas llamadas <strong>de</strong> ánimo y apoyo.<br />
Pero no puedo terminar, sin agra<strong>de</strong>cer al artífice <strong>de</strong> que diera el paso <strong>de</strong>finitivo para comenzar<br />
con el proyecto, David mi director. Gracias por tu paciencia, por hacerme ver las<br />
cosas fáciles cuando las veía difíciles y sobre todo por compartir tus conocimientos y tu<br />
tiempo conmigo.<br />
Carlos<br />
XIII
Índice general<br />
Resumen<br />
Agra<strong>de</strong>cimientos<br />
Índice general<br />
Índice <strong>de</strong> cuadros<br />
Índice <strong>de</strong> figuras<br />
Índice <strong>de</strong> listados<br />
Listado <strong>de</strong> acrónimos<br />
IX<br />
XIII<br />
XV<br />
XXI<br />
XXIII<br />
XXV<br />
XXIX<br />
1. Introducción 1<br />
1.1. Estructura <strong>de</strong>l documento . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />
2. Antece<strong>de</strong>ntes 5<br />
2.1. Hojas <strong>de</strong> cálculo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />
2.1.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />
2.1.2. Conceptos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />
2.1.3. Principales aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo . . . . . . . . . . . . . 7<br />
2.2. Alternativas para trabajar con hojas <strong>de</strong> cálculo . . . . . . . . . . . . . . . . 7<br />
2.2.1. Estudio e implementación <strong>de</strong> los estándares . . . . . . . . . . . . . 8<br />
2.2.2. Microsoft Office y COM . . . . . . . . . . . . . . . . . . . . . . . 9<br />
2.2.3. OpenOffice.org y UNO . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
2.2.4. Apache POI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
2.2.5. Spreadsheet::ParseExcel . . . . . . . . . . . . . . . . . . . . . . . 19<br />
2.2.6. Spreadsheet::Read . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.2.7. Spreadsheet::WriteExcel . . . . . . . . . . . . . . . . . . . . . . . 22<br />
2.2.8. OpenOffice::OODoc . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />
XV
2.2.9. Java Excel API . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />
2.2.10. GemBox.SpreadSheet . . . . . . . . . . . . . . . . . . . . . . . . 27<br />
2.2.11. Spreadsheet SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />
2.2.12. Comparativa <strong>de</strong> alternativas . . . . . . . . . . . . . . . . . . . . . 29<br />
3. Objetivos <strong>de</strong>l proyecto 33<br />
3.1. Objetivo general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
3.2. Objetivos específicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
3.2.1. Objetivo 1: Formatos soportados . . . . . . . . . . . . . . . . . . . 34<br />
3.2.2. Objetivo 2: Operaciones permitidas . . . . . . . . . . . . . . . . . 34<br />
3.2.3. Objetivo 3: Conversiones entre formatos . . . . . . . . . . . . . . . 35<br />
3.2.4. Objetivo 4: Exportación a pdf . . . . . . . . . . . . . . . . . . . . 35<br />
3.2.5. Objetivo 5: Multiplataforma . . . . . . . . . . . . . . . . . . . . . 35<br />
3.2.6. Objetivo 6: Librería . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
3.2.7. Objetivo 7: Comando . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
3.2.8. Objetivo 8: Servicio web . . . . . . . . . . . . . . . . . . . . . . . 36<br />
4. Método y entorno <strong>de</strong> trabajo 37<br />
4.1. Método <strong>de</strong> trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
4.1.1. Metodologías Ágiles . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
4.1.2. Scrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />
4.1.3. Adaptación <strong>de</strong> Scrum al marco <strong>de</strong> trabajo . . . . . . . . . . . . . . 43<br />
4.1.4. Desarrollo dirigido por tests . . . . . . . . . . . . . . . . . . . . . 48<br />
4.1.5. Adaptación <strong>de</strong> TDD al marco <strong>de</strong> trabajo . . . . . . . . . . . . . . . 49<br />
4.2. Entorno <strong>de</strong> trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />
4.2.1. Herramientas <strong>de</strong> <strong>de</strong>sarrollo . . . . . . . . . . . . . . . . . . . . . . 50<br />
4.2.2. Lenguajes <strong>de</strong> programación . . . . . . . . . . . . . . . . . . . . . 52<br />
4.2.3. Herramientas <strong>de</strong> documentación . . . . . . . . . . . . . . . . . . . 53<br />
4.2.4. Sistemas Operativos . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />
5. Resultados 55<br />
5.1. Análisis y planificación . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />
5.1.1. Análisis <strong>de</strong> requisitos . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />
5.1.2. Estudio <strong>de</strong> viabilidad <strong>de</strong> alternativas . . . . . . . . . . . . . . . . . 58<br />
5.1.3. Planificación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
5.2. Sprint 1: Creación y almacenamiento <strong>de</strong> documentos . . . . . . . . . . . . 64
5.2.1. Historia 1.1 - Crear nuevos documentos . . . . . . . . . . . . . . . 65<br />
5.2.2. Historia 1.5 - Convertir el formato <strong>de</strong>l documento . . . . . . . . . . 69<br />
5.2.3. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />
5.3. Sprint 2: Apertura <strong>de</strong> documentos y modificación <strong>de</strong> hojas . . . . . . . . . 70<br />
5.3.1. Historia 1.2 - Abrir documentos . . . . . . . . . . . . . . . . . . . 71<br />
5.3.2. Historia 1.3 - Modificar hojas <strong>de</strong> cálculo <strong>de</strong> un documento . . . . . 73<br />
5.3.3. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />
5.4. Sprint 3: Modificación <strong>de</strong> celdas . . . . . . . . . . . . . . . . . . . . . . . 76<br />
5.4.1. Historia 1.4 - Insertar valores en celdas . . . . . . . . . . . . . . . 77<br />
5.4.2. Historia 1.6 - Extraer valores <strong>de</strong> celdas . . . . . . . . . . . . . . . 79<br />
5.4.3. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />
5.5. Sprint 4: Estudio <strong>de</strong> lenguaje script y comando . . . . . . . . . . . . . . . 81<br />
5.5.1. Historia 2.1 - Estudio <strong>de</strong> lenguaje script . . . . . . . . . . . . . . . 83<br />
5.5.2. Historia 2.2 - Comando para ejecutar scripts . . . . . . . . . . . . . 84<br />
5.5.3. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />
5.6. Sprint 5: Script genérico para el comando . . . . . . . . . . . . . . . . . . 87<br />
5.6.1. Historia 2.3 - Script Genérico . . . . . . . . . . . . . . . . . . . . 87<br />
5.6.2. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />
5.7. Sprint 6: Servicio web . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />
5.7.1. Historia 3.1 - Operación <strong>de</strong> listado <strong>de</strong> scripts . . . . . . . . . . . . 90<br />
5.7.2. Historia 3.2 - Operación <strong>de</strong> selección y ejecución <strong>de</strong> un script sobre<br />
un documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />
5.7.3. Resumen <strong>de</strong> sprint . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />
5.8. Sprints 7-10: Documentación . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />
5.8.1. Sprint 7: Documentación 1 - Antece<strong>de</strong>ntes . . . . . . . . . . . . . 95<br />
5.8.2. Sprint 8: Documentación 2 - Objetivos y Método <strong>de</strong> Trabajo . . . . 96<br />
5.8.3. Sprint 9: Documentación 3 - Resultados . . . . . . . . . . . . . . . 97<br />
5.8.4. Sprint 10: Documentación 4 - Conclusiones e Introducción . . . . . 97<br />
5.9. API OpenSheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />
5.10. Comando OpenSheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
5.11. Servicio web OpenSheet . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
5.12. Documentación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />
5.13. Estadísticas <strong>de</strong>l proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />
6. Conclusiones 105<br />
6.1. Objetivos alcanzados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
6.2. Posibles mejoras y ampliaciones . . . . . . . . . . . . . . . . . . . . . . . 107<br />
6.2.1. Uso <strong>de</strong> OpenOffice.org remoto . . . . . . . . . . . . . . . . . . . . 107<br />
6.2.2. Soporte para fórmulas . . . . . . . . . . . . . . . . . . . . . . . . 107<br />
6.2.3. Añadir nuevos tipos para la inserción <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias . . . . . . . 108<br />
6.2.4. Crear nuevos scripts para uso general . . . . . . . . . . . . . . . . 109<br />
6.2.5. Permitir <strong>de</strong>pen<strong>de</strong>ncias entre scripts . . . . . . . . . . . . . . . . . 109<br />
6.3. Conclusiones personales . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />
6.3.1. Conclusiones sobre la metodología <strong>de</strong> planificación . . . . . . . . . 110<br />
6.3.2. Conclusiones sobre la metodología <strong>de</strong> <strong>de</strong>sarrollo . . . . . . . . . . 110<br />
A. Manual <strong>de</strong> usuario 115<br />
A.1. OpenSheet Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
A.1.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
A.1.2. Operación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116<br />
A.1.3. Formato <strong>de</strong> fichero <strong>de</strong> datos . . . . . . . . . . . . . . . . . . . . . 116<br />
A.1.4. Uso <strong>de</strong>l script OpenSheetScript.groovy . . . . . . . . . . . . . . . 118<br />
A.1.5. Ejemplo <strong>de</strong> uso <strong>de</strong> OpenSheet Command . . . . . . . . . . . . . . 127<br />
A.2. OpenSheet Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
A.2.1. Requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
A.2.2. Despliegue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
A.2.3. Fichero web.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
A.2.4. Activar scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />
A.2.5. Clientes <strong>de</strong> OpenSheet Web Service . . . . . . . . . . . . . . . . . 131<br />
B. Manual <strong>de</strong> <strong>de</strong>sarrollo 133<br />
B.1. Direcciones <strong>de</strong> interés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
B.1.1. Repositorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
B.1.2. Gestión <strong>de</strong> inci<strong>de</strong>ncias y peticiones <strong>de</strong> mejora . . . . . . . . . . . . 134<br />
B.2. OpenSheet API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />
B.2.1. Ejemplos <strong>de</strong> uso . . . . . . . . . . . . . . . . . . . . . . . . . . . 135<br />
B.2.2. Clases y métodos principales . . . . . . . . . . . . . . . . . . . . . 138<br />
B.3. OpenSheet Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />
B.3.1. Clases y métodos principales . . . . . . . . . . . . . . . . . . . . . 141<br />
B.3.2. Creación <strong>de</strong> nuevos scripts . . . . . . . . . . . . . . . . . . . . . . 141<br />
B.4. OpenSheet Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
B.4.1. Clases y métodos principales . . . . . . . . . . . . . . . . . . . . . 143
B.4.2. Creación <strong>de</strong> nuevos scripts . . . . . . . . . . . . . . . . . . . . . . 143<br />
B.4.3. Pasos <strong>de</strong> la operación executeScript . . . . . . . . . . . . . . . . . 144<br />
B.4.4. Cliente <strong>de</strong> ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
C. GNU Free Documentation License 149<br />
C.0. PREAMBLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149<br />
C.1. APPLICABILITY AND DEFINITIONS . . . . . . . . . . . . . . . . . . . 149<br />
C.2. VERBATIM COPYING . . . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />
C.3. COPYING IN QUANTITY . . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />
C.4. MODIFICATIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />
C.5. COLLECTIONS OF DOCUMENTS . . . . . . . . . . . . . . . . . . . . . 152<br />
C.6. AGGREGATION WITH INDEPENDENT WORKS . . . . . . . . . . . . 152<br />
C.7. TRANSLATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
C.8. TERMINATION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
C.9. FUTURE REVISIONS OF THIS LICENSE . . . . . . . . . . . . . . . . . 153<br />
C.10. RELICENSING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
Bibliografía 155
Índice <strong>de</strong> cuadros<br />
2.1. Comparativa <strong>de</strong> funcionalida<strong>de</strong>s <strong>de</strong> las distintas alternativas . . . . . . . . . 30<br />
2.2. Comparativa <strong>de</strong> características generales <strong>de</strong> las alternativas . . . . . . . . . 31<br />
5.1. Pila <strong>de</strong> producto inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />
5.2. Historias añadidas al Sprint 1 . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />
5.3. Historias añadidas al Sprint 2 . . . . . . . . . . . . . . . . . . . . . . . . . 72<br />
5.4. Historias añadidas al Sprint 3 . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />
5.5. Historias añadidas al Sprint 4 . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />
5.6. Historias añadidas al Sprint 5 . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
5.7. Historias añadidas al Sprint 6 . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
5.8. Historias añadidas al Sprint 7 . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />
5.9. Historias añadidas al Sprint 8 . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />
5.10. Historias añadidas al Sprint 9 . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />
5.11. Historias añadidas al Sprint 10 . . . . . . . . . . . . . . . . . . . . . . . . 97<br />
5.12. Resultado <strong>de</strong> ejecución <strong>de</strong> SLOCCount con src . . . . . . . . . . . . . . . 103<br />
5.13. Resultado <strong>de</strong> ejecución <strong>de</strong> SLOCCount test . . . . . . . . . . . . . . . . . 103<br />
XXI
Índice <strong>de</strong> figuras<br />
4.1. Roles <strong>de</strong> Scrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42<br />
4.2. Representación <strong>de</strong> un sprint <strong>de</strong> Scrum . . . . . . . . . . . . . . . . . . . . 43<br />
4.3. Ejemplo <strong>de</strong> gráfico <strong>de</strong> burndown <strong>de</strong> un sprint . . . . . . . . . . . . . . . . 44<br />
4.4. Algoritmo TDD: Rojo, Ver<strong>de</strong>, Refactorizar. . . . . . . . . . . . . . . . . . 49<br />
5.1. Diagrama <strong>de</strong> casos <strong>de</strong> uso básico <strong>de</strong> API . . . . . . . . . . . . . . . . . . . 56<br />
5.2. Diagrama <strong>de</strong> casos <strong>de</strong> uso básico <strong>de</strong>l comando y servicio web . . . . . . . . 57<br />
5.3. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 1 . . . . . . . . . . . . . . . . . . . . . . . 70<br />
5.4. Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 1 . . . . . . . . . . . . . . . . . . 71<br />
5.5. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 2 . . . . . . . . . . . . . . . . . . . . . . . 75<br />
5.6. Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 2 . . . . . . . . . . . . . . . . . . 76<br />
5.7. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 3 . . . . . . . . . . . . . . . . . . . . . . . 81<br />
5.8. Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 3 . . . . . . . . . . . . . . . . . . 82<br />
5.9. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 4 . . . . . . . . . . . . . . . . . . . . . . . 86<br />
5.10. Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 4 . . . . . . . . . . . . . . . . . . 86<br />
5.11. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 5 . . . . . . . . . . . . . . . . . . . . . . . 89<br />
5.12. Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 6 . . . . . . . . . . . . . . . . . . . . . . . 95<br />
5.13. Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 6 . . . . . . . . . . . . . . . . . . 96<br />
5.14. Diagrama <strong>de</strong> clases <strong>de</strong> la API <strong>de</strong> OpenSheet . . . . . . . . . . . . . . . . . 98<br />
5.15. Diagrama <strong>de</strong> clases <strong>de</strong>l Comando <strong>de</strong> OpenSheet . . . . . . . . . . . . . . . 100<br />
5.16. Diagrama <strong>de</strong> clases <strong>de</strong>l Servicio Web <strong>de</strong> OpenSheet . . . . . . . . . . . . . 101<br />
XXIII
Índice <strong>de</strong> listados<br />
2.1. Cómo cargar la aplicación Excel para ser usada través <strong>de</strong> COM . . . . . . . 10<br />
2.2. Cómo hacer que la carga <strong>de</strong>l servicio COM sea en segundo plano . . . . . . 10<br />
2.3. Abrir un fichero Excel a través <strong>de</strong> COM . . . . . . . . . . . . . . . . . . . 11<br />
2.4. Seleccionar una hoja <strong>de</strong> cálculo a través <strong>de</strong> su nombre usando COM . . . . 11<br />
2.5. Arracar OpenOffice.org en modo servicio escuchando en un socket . . . . . 13<br />
2.6. Arracar OpenOffice.org en modo servicio escuchando en una tubería o pipe 13<br />
2.7. Ca<strong>de</strong>na <strong>de</strong> conexión para conectar con un servicio a través <strong>de</strong> socket . . . . 13<br />
2.8. Ca<strong>de</strong>na <strong>de</strong> conexión para conectar con un servicio a través <strong>de</strong> una tubería o<br />
pipe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
2.9. Ejemplo uso UNO parte 1: Cómo obtener el objeto remoto XComponentLoa<strong>de</strong>r 14<br />
2.10. Ejemplo uso UNO parte 2: Cómo crear un nuevo documento <strong>de</strong> hojas <strong>de</strong><br />
cálculo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />
2.11. Ejemplo uso UNO parte 3: Añadir una nueva hoja <strong>de</strong> cálculo al documento 15<br />
2.12. Ejemplo uso UNO parte 4: Insertar valores a celdas . . . . . . . . . . . . . 16<br />
2.13. Ejemplo uso UNO parte 5: Guardar un documento con formato xls . . . . . 16<br />
2.14. Ejemplo uso Apache POI . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
2.15. Ejemplo uso Spreadsheet::ParseExcel . . . . . . . . . . . . . . . . . . . . 19<br />
2.16. Ejemplo uso Spreadsheet::Read . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.17. Ejemplo <strong>de</strong> la estructura <strong>de</strong> datos <strong>de</strong> un documento <strong>de</strong> Spreadsheet::Read . 21<br />
2.18. Ejemplo uso Spreadsheet::WriteExcel . . . . . . . . . . . . . . . . . . . . 23<br />
2.19. Ejemplo uso OpenOffice::OODoc . . . . . . . . . . . . . . . . . . . . . . 24<br />
2.20. Ejemplo uso Java Excel API . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />
2.21. Ejemplo uso GemBox.SpreadSheet . . . . . . . . . . . . . . . . . . . . . . 27<br />
2.22. Ejemplo uso Spreadsheet SDK . . . . . . . . . . . . . . . . . . . . . . . . 28<br />
5.1. Añadiendo un directorio a Java Library Path . . . . . . . . . . . . . . . . . 66<br />
5.2. Cambio la localización <strong>de</strong>l path <strong>de</strong>l ejecutable en la clase Bootstrap . . . . 67<br />
A.1. Ejecución OpenSheet Command . . . . . . . . . . . . . . . . . . . . . . . 116<br />
A.2. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetManager; . . . . . . . . . 116<br />
A.3. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetDocument; para crear un<br />
documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<br />
XXV
A.4. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetDocument; para abrir un<br />
documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<br />
A.5. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @number; . . . . . . . . . . . . . . . 117<br />
A.6. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list; . . . . . . . . . . . . . . . . . . 118<br />
A.7. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list; con escape <strong>de</strong>l separador . . . . 118<br />
A.8. Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list; con ca<strong>de</strong>nas vacias . . . . . . . 118<br />
A.9. Ejemplo <strong>de</strong> asignación <strong>de</strong> nuevo documento a la variable openSheetDocument<br />
<strong>de</strong> OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />
A.10.Ejemplo <strong>de</strong> asignación <strong>de</strong> un documento a la variable openSheetDocument<br />
<strong>de</strong> OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />
A.11.Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable logFileName . . . . . . . . . . . 121<br />
A.12.Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable logFileName <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />
A.13.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable <strong>de</strong>leteSheets <strong>de</strong> OpenSheetScript122<br />
A.14.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable <strong>de</strong>leteSheetsByPosition <strong>de</strong><br />
OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122<br />
A.15.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores repetidos a la variable <strong>de</strong>leteSheetsByPosition<br />
<strong>de</strong> OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . . . 122<br />
A.16.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable addSheets <strong>de</strong> OpenSheetScript 123<br />
A.17.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123<br />
A.18.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />
A.19.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />
A.20.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
A.21.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable extractCellsValues <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
A.22.Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable extractCellsValuesBySheet-<br />
Position <strong>de</strong> OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />
A.23.Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable extractCellsValuesFile . . . . . . 126<br />
A.24.Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable extractCellsValuesFile <strong>de</strong><br />
OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />
A.25.Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable saveDocumentTo . . . . . . . . . 127<br />
A.26.Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable saveDocumentTo <strong>de</strong> OpenSheetScript<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />
A.27.Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero con extensión PDF a la variable save-<br />
DocumentTo <strong>de</strong> OpenSheetScript . . . . . . . . . . . . . . . . . . . . . . . 127
A.28.Ejemplo <strong>de</strong> fichero <strong>de</strong> datos . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />
A.29.Ejemplo <strong>de</strong> fichero Properties para script <strong>de</strong> servicio web . . . . . . . . . . 131<br />
B.1. Crear un nuevo documento con OpenSheet API . . . . . . . . . . . . . . . 135<br />
B.2. Abrir un documento con OpenSheet API . . . . . . . . . . . . . . . . . . . 135<br />
B.3. Insertar datos a celdas con OpenSheet API . . . . . . . . . . . . . . . . . . 136<br />
B.4. Insertar datos a rangos con OpenSheet API . . . . . . . . . . . . . . . . . 136<br />
B.5. Extraer datos <strong>de</strong> celdas con OpenSheet API . . . . . . . . . . . . . . . . . 137<br />
B.6. Extraer datos <strong>de</strong> rangos <strong>de</strong> celdas con OpenSheet API . . . . . . . . . . . . 137<br />
B.7. Añadir hojas <strong>de</strong> cálculo con OpenSheet API . . . . . . . . . . . . . . . . . 138<br />
B.8. Borrar hojas <strong>de</strong> cálculo con OpenSheet API . . . . . . . . . . . . . . . . . 138<br />
B.9. Convertir un documento <strong>de</strong> un formato a otro con OpenSheet API . . . . . 138<br />
B.10. Exportar un documento a formato PDF con OpenSheet API . . . . . . . . . 139<br />
B.11. Ejemplo <strong>de</strong> fichero Properties para script <strong>de</strong> servicio web . . . . . . . . . . 145<br />
B.12. Ejemplo <strong>de</strong> cliente <strong>de</strong> OpenSheet Web Service - Parte 1 . . . . . . . . . . . 147<br />
B.13. Ejemplo <strong>de</strong> cliente <strong>de</strong> OpenSheet Web Service - Parte 2 . . . . . . . . . . . 148
Listado <strong>de</strong> acrónimos<br />
GNU<br />
API<br />
OOO<br />
XML<br />
COM<br />
OLE<br />
MFC<br />
UNO<br />
URL<br />
SDK<br />
PDF<br />
GPL<br />
LGPL<br />
CSV<br />
IDE<br />
JDK<br />
EE<br />
JVM<br />
UML<br />
TDD<br />
XP<br />
SLOC<br />
GNU is Not Unix<br />
Application Programming Interface<br />
OpenOffice.org<br />
Extensible Markup <strong>La</strong>nguage<br />
Component Object Mo<strong>de</strong>l<br />
Object Linking and Embedding<br />
Microsoft Fundations Classes<br />
Universal Network Objects<br />
Uniform Resource Locator<br />
Software Development Kit<br />
Portable Document Format<br />
General Public License<br />
Lesser General Public License<br />
Comma-Separated Values<br />
Integrated Development Environment<br />
Java Development Kit<br />
Enterprise Edition<br />
Java Virtual Machine<br />
Unified Mo<strong>de</strong>lling <strong>La</strong>nguage<br />
Test Driven Development<br />
eXtreme Programming<br />
Source Lines Of Co<strong>de</strong><br />
XXIX
Capítulo 1<br />
Introducción<br />
LAs aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo son programas que permiten la creación y manipulación<br />
<strong>de</strong> documentos compuestos por una cuadrícula con múltiples celdas or<strong>de</strong>nadas<br />
por fila y columna, y que pue<strong>de</strong>n contener datos numéricos, alfanuméricos o fórmulas. <strong>La</strong>s<br />
fórmulas permiten indicar cómo el contenido <strong>de</strong> una celda <strong>de</strong>be ser calculado a partir <strong>de</strong> otra<br />
celda o grupo <strong>de</strong> celdas.<br />
<strong>La</strong>s hojas <strong>de</strong> cálculo son consi<strong>de</strong>radas por algunos autores como un lenguaje <strong>de</strong> programación<br />
funcional [RA09], don<strong>de</strong> el usuario <strong>de</strong> manera visual y directa genera programas <strong>de</strong><br />
cálculo sin necesidad <strong>de</strong> conocimientos previos <strong>de</strong> programación. Gracias a su facilidad <strong>de</strong><br />
uso, a la gran cantidad <strong>de</strong> funciones que proporcionan y a la intercomunicación con otras<br />
aplicaciones, las hojas <strong>de</strong> cálculo ofrecen una gran versatilidad que ha hecho que su uso sea<br />
muy extendido y variado en campos muy diversos. <strong>La</strong>s hojas <strong>de</strong> cálculo son usadas como herramienta<br />
en las ingenierías [CTC06, Fre92, Arg93] <strong>de</strong>bido a su gran potencia para realizar<br />
cálculos y a la facilidad para automatizarlos a través <strong>de</strong> fórmulas; y sobre todo son usadas<br />
por muchas empresas y organizaciones para realizar cálculos financieros, guardar informes,<br />
gráficos estadísticos, clasificación <strong>de</strong> datos, etc. Convirtiéndose estos documentos en una<br />
fuente importante <strong>de</strong> datos.<br />
Es <strong>de</strong>bido al papel tan importante que juegan las hojas <strong>de</strong> cálculo, en las empresas y organizaciones,<br />
que un simple error en una hoja <strong>de</strong> cálculo pue<strong>de</strong> ocasionar gran<strong>de</strong>s pérdidas [Gro].<br />
Por ello se han realizado diferentes estudios que han dado como resultado, la i<strong>de</strong>ntificación<br />
<strong>de</strong> riesgos para cada tipo <strong>de</strong> organización [BFJLP07], las diferencias <strong>de</strong> uso entre usuarios<br />
con diferente grado <strong>de</strong> experiencia [LBPFJ07], y lo más importante un conjunto <strong>de</strong> buenas<br />
prácticas [NR99] en el diseño y mo<strong>de</strong>lado <strong>de</strong> hojas <strong>de</strong> cálculo proponiendo un ciclo <strong>de</strong> vida<br />
que se adapta a las diferentes necesida<strong>de</strong>s según el tipo <strong>de</strong> mo<strong>de</strong>lo.<br />
En el mercado existen diferentes alternativas en lo que a aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo<br />
se refiere, y cada una <strong>de</strong> ellas con su propio formato, pero la más utilizada y extendida es<br />
Microsoft Excel [SL99], con su formato xls [Mic08b] [Mic08a], que se proporciona <strong>de</strong>ntro<br />
<strong>de</strong> la suite <strong>de</strong> aplicaciones <strong>de</strong> oficina Microsoft Office, y que se impuso en los 90 a la suite<br />
Lotus 1-2-3 <strong>de</strong> IBM y a su formato [Cor84].<br />
Como alternativa libre, <strong>de</strong>staca la suite OpenOffice.org [ope], que incluye la aplicación <strong>de</strong><br />
1
2 1. INTRODUCCIÓN<br />
hojas <strong>de</strong> cálculo Calc. Esta suite ha ido ganando cada vez más mercado al permitir la utilización<br />
<strong>de</strong> otros formatos como los <strong>de</strong> Microsoft Office, y al utilizar como formato nativo Open<br />
Document Format [OAS07] [OAS10], formato estándar <strong>de</strong> la organización OASIS [oas],<br />
para garantizar que los documentos generados no que<strong>de</strong>n atados a una única aplicación.<br />
Según lo <strong>de</strong>scrito, son muchas las organizaciones que cuentan con un gran número <strong>de</strong><br />
hojas <strong>de</strong> cálculo que contienen a su vez gran cantidad <strong>de</strong> datos, por lo que sería <strong>de</strong>seable el<br />
po<strong>de</strong>r contar con una herramienta que permita la extracción e inserción <strong>de</strong> datos en hojas<br />
<strong>de</strong> cálculo <strong>de</strong> manera automática. Permitiendo así utilizar en otras aplicaciones los datos<br />
almacenados en hojas <strong>de</strong> cálculo, a través <strong>de</strong> la extracción <strong>de</strong> datos; y viceversa, utilizar los<br />
datos disponibles en otras aplicaciones en las hojas <strong>de</strong> cálculo a través <strong>de</strong> la inserción <strong>de</strong><br />
datos.<br />
A<strong>de</strong>más, a pesar <strong>de</strong> los estudios mencionados anteriormente sobre buenas prácticas para<br />
el diseño <strong>de</strong> hojas <strong>de</strong> cálculo, sigue habiendo un mal uso a la hora <strong>de</strong> mo<strong>de</strong>lar hojas <strong>de</strong> cálculo<br />
[BFJLP06], y muchas otras hojas <strong>de</strong> cálculo que ya se encuentran en uso, siendo inviable<br />
volverlas a mo<strong>de</strong>lar usando el conjunto <strong>de</strong> buenas prácticas propuestas; por lo tanto la estrategia<br />
en este caso <strong>de</strong>be ir encaminada a <strong>de</strong>tectar los posibles errores para eliminarlos, <strong>de</strong><br />
manera que dichas hojas <strong>de</strong> cálculo sean correctas y estén libres <strong>de</strong> errores. Para ello se <strong>de</strong>ben<br />
realizar pruebas con el objetivo <strong>de</strong> <strong>de</strong>purar las hojas <strong>de</strong> cálculo [RA08] y así po<strong>de</strong>r garantizar<br />
un mínimo <strong>de</strong> calidad, para evitar riesgos y pérdidas como se comentó anteriormente.<br />
Esta tarea <strong>de</strong> pruebas se facilitaría mucho si se contara con la herramienta mencionada anteriormente,<br />
puesto que permitiría automatizar las pruebas, usando un conjunto <strong>de</strong> datos <strong>de</strong><br />
entrada que insertaría <strong>de</strong> manera automática, y extrayendo los datos obtenidos para que otro<br />
programa los comparara con los datos esperados.<br />
Aunque las aplicaciones como Microsoft Excel permiten la automatización <strong>de</strong> algunas<br />
tareas a través <strong>de</strong>l uso <strong>de</strong> macros escritas en lenguajes <strong>de</strong> tipo script como Visual Basic<br />
[Wal10], sería <strong>de</strong>seable una herramienta que permita trabajar con los principales formatos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo, y no sólo con el formato nativo <strong>de</strong> la aplicación don<strong>de</strong> se ejecuta la macro;<br />
a<strong>de</strong>más, sería <strong>de</strong>seable que permitiera <strong>de</strong> manera sencilla automatizar diferentes tareas<br />
sin necesidad <strong>de</strong> utilizar una interfaz gráfica.<br />
Por todas las necesida<strong>de</strong>s anteriores se plantea el diseño <strong>de</strong> OpenSheet, un proyecto cuyo<br />
objetivo principal es la extracción e inserción <strong>de</strong> datos en hojas <strong>de</strong> cálculo <strong>de</strong> manera automática<br />
y sencilla, soportando los principales formatos <strong>de</strong> los productos Microsoft Excel y<br />
OpenOffice.org Calc.<br />
1.1. Estructura <strong>de</strong>l documento<br />
El presente documento se encuentra dividido en los diferentes capítulos establecidos por<br />
la normativa académica para proyectos fin <strong>de</strong> carrera [dIU07]. El autor recomienda leer cada
1. INTRODUCCIÓN 3<br />
uno <strong>de</strong> los capítulos <strong>de</strong> manera secuencial para una mejor comprensión.<br />
Los capítulos que pue<strong>de</strong> encontrar el lector en el documento son los siguientes:<br />
Capítulo 2: Antece<strong>de</strong>ntes En este capítulo primero se <strong>de</strong>finen los principales conceptos<br />
básicos relacionados con los documentos <strong>de</strong> hojas <strong>de</strong> cálculo, necesarios para po<strong>de</strong>r<br />
compren<strong>de</strong>r el proyecto. Y <strong>de</strong>spués, se explican las alternativas, para trabajar con hojas<br />
<strong>de</strong> cálculo, analizadas en un estudio comparativo.<br />
Capítulo 3: Objetivos <strong>de</strong>l proyecto En este capítulo se explica <strong>de</strong> manera <strong>de</strong>tallada qué<br />
se quiere lograr con el proyecto. Para ello se <strong>de</strong>scriben todos los objetivos que se<br />
persiguen, tanto el objetivo general como los objetivos específicos.<br />
Capítulo 4: Método y entorno <strong>de</strong> trabajo En este capítulo se explican los principales conceptos<br />
<strong>de</strong> las metodologías aplicadas al <strong>de</strong>sarrollo <strong>de</strong>l proyecto, y también se <strong>de</strong>scribe<br />
las herramientas o aplicaciones software que han formado parte <strong>de</strong>l entorno <strong>de</strong> trabajo.<br />
Capítulo 5: Resultados En este capítulo se explica cómo se ha llevado a cabo las metodologías<br />
elegidas, <strong>de</strong>scritas en el capítulo 4, para lograr alcanzar los objetivos marcados<br />
al comienzo <strong>de</strong>l proyecto.<br />
Capítulo 6: Conclusiones En este capítulo se presentan diferentes contenidos relacionados<br />
con las conclusiones <strong>de</strong>l proyecto. Por un lado se <strong>de</strong>scribe cómo se han logrado cubrir<br />
los objetivos marcados al comienzo <strong>de</strong>l proyecto. Por otro lado se <strong>de</strong>scriben diferentes<br />
propuestas que pue<strong>de</strong>n ser llevadas a cabo en futuros <strong>de</strong>sarrollos, y que han quedado<br />
fuera <strong>de</strong>l alcance <strong>de</strong>l proyecto. Y por último, se incluye una sección don<strong>de</strong> el autor<br />
comenta sus conclusiones personales acerca <strong>de</strong> la experiencia adquirida durante el<br />
<strong>de</strong>sarrollo <strong>de</strong>l proyecto.
Capítulo 2<br />
Antece<strong>de</strong>ntes<br />
EN este capítulo se preten<strong>de</strong> por un lado dar una breve explicación sobre qué es una hoja<br />
<strong>de</strong> cálculo y los conceptos que incorpora; y por otro lado ofrecer una visión general<br />
<strong>de</strong> las diferentes alternativas existentes <strong>de</strong> librerías y APIs <strong>de</strong> programación que permiten<br />
al <strong>de</strong>sarrollador, mediante su incorporación en aplicaciones, realizar diferentes operaciones<br />
con documentos <strong>de</strong> hojas <strong>de</strong> cálculo sin necesidad <strong>de</strong> utilizar ninguna interfaz gráfica.<br />
2.1. Hojas <strong>de</strong> cálculo<br />
2.1.1. Introducción<br />
Una aplicación <strong>de</strong> hojas <strong>de</strong> cálculo es un programa que permite crear y editar documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo. Estos documentos están compuestos por una cuadrícula con múltiples<br />
celdas or<strong>de</strong>nadas por fila y columna, que pue<strong>de</strong>n contener datos <strong>de</strong> diferentes tipos: numéricos,<br />
alfanuméricos o fórmulas.<br />
<strong>La</strong>s fórmulas permiten indicar cómo el contenido <strong>de</strong> una celda <strong>de</strong>be ser calculado a partir<br />
<strong>de</strong> otra celda o grupo <strong>de</strong> celdas. <strong>La</strong>s fórmulas son uno <strong>de</strong> los principales causantes que han<br />
hecho que hoy en día las aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo tengan un uso muy extendido en<br />
campos muy diversos. Esto es <strong>de</strong>bido a que las fórmulas permiten realizar y automatizar<br />
cálculos complejos <strong>de</strong> manera muy sencilla.<br />
Debido a su gran uso y a la potencia <strong>de</strong> los cálculos permitidos, los documentos <strong>de</strong> hojas<br />
<strong>de</strong> cálculo son una fuente importante <strong>de</strong> datos para empresas y organizaciones.<br />
A continuación, se realizará una breve <strong>de</strong>scripción <strong>de</strong> los conceptos necesarios para po<strong>de</strong>r<br />
enten<strong>de</strong>r mejor qué es una hoja <strong>de</strong> cálculo.<br />
2.1.2. Conceptos<br />
En este apartado se preten<strong>de</strong> explicar aquellos conceptos necesarios para enten<strong>de</strong>r mejor<br />
el concepto <strong>de</strong> hoja <strong>de</strong> cálculo y los elementos que lo componen, y por tanto para facilitar la<br />
comprensión <strong>de</strong> este documento.<br />
5
6 2. ANTECEDENTES<br />
Hoja <strong>de</strong> cálculo<br />
Aunque en la introducción <strong>de</strong> esta sección ya se ha dado una <strong>de</strong>finición <strong>de</strong> la palabra<br />
hoja <strong>de</strong> cálculo, en inglés spreadsheet, dicha palabra es usada <strong>de</strong> manera habitual para hacer<br />
referencia a distintos conceptos, y para evitar confundir al lector, en este documento siempre<br />
se usará un único significado.<br />
Una hoja <strong>de</strong> cálculo es una cuadrícula con múltiples celdas or<strong>de</strong>nadas por fila y columna,<br />
que pue<strong>de</strong>n contener datos numéricos, alfanuméricos o fórmulas.<br />
Celda<br />
Una celda, en inglés cell, es el elemento que forma la cuadrícula <strong>de</strong> una la hoja <strong>de</strong> cálculo,<br />
y don<strong>de</strong> se sitúa una fórmula o un dato, ya sea numérico o alfanumérico.<br />
Una celda es i<strong>de</strong>ntificada por una columna y una fila. Normalmente para nombrar o i<strong>de</strong>ntificar<br />
las columnas se usan letras y para las filas se utilizan números enteros, por tanto, una<br />
celda cuyo nombre sea A1 hará referencia a la celda con posición fila 0 y columna 0 en la<br />
cuadrícula.<br />
Rango<br />
Un rango, en inglés range, es un conjunto contiguo <strong>de</strong> celdas i<strong>de</strong>ntificados mediante el<br />
i<strong>de</strong>ntificador <strong>de</strong> la celda superior izquierda y el i<strong>de</strong>ntificador <strong>de</strong> la celda inferior izquierda,<br />
normalmente separado por dos puntos.<br />
El rango permite manejar un conjunto <strong>de</strong> celdas como una única entidad, facilitando operar<br />
con ellas.<br />
Documento <strong>de</strong> hojas <strong>de</strong> cálculo<br />
Un documento <strong>de</strong> hojas <strong>de</strong> cálculo, en inglés spreadsheet document, como su nombre<br />
indica, es un documento o fichero que se compone <strong>de</strong> diferentes hojas <strong>de</strong> cálculo cada una<br />
<strong>de</strong> ellas i<strong>de</strong>ntificada por un nombre o una posición lineal.<br />
Es habitual usar la palabra hoja <strong>de</strong> cálculo, en inglés spreadsheet, para referirse a un documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo. Y puesto que en inglés para referirse a las hojas <strong>de</strong> cálculo que<br />
componen un documento se utilizan las palabras sheets o worksheets, no existe problema<br />
para distinguir en una misma frase cuando se hace referencia al documento o una hoja propiamente<br />
dicha, el problema existe en castellano pues la traducción <strong>de</strong> las palabras anteriores<br />
es hoja u hoja <strong>de</strong> cálculo respectivamente, lo que impi<strong>de</strong> usar esa nomenclatura sin llevar a<br />
confusión; por tanto se evitará en este documento.
2. ANTECEDENTES 7<br />
Aplicación <strong>de</strong> hojas <strong>de</strong> cálculo<br />
Una aplicación <strong>de</strong> hojas <strong>de</strong> cálculo es programa que opera con tablas formadas por filas y<br />
columnas <strong>de</strong> celdas que contienen información numérica y fórmulas o texto, y las presenta en<br />
una pantalla. Esta es la <strong>de</strong>finición dada por la Real Aca<strong>de</strong>mia Española para la palabra hoja<br />
<strong>de</strong> cálculo pues pue<strong>de</strong> ser usada también para nombrar a la aplicación propiamente dicha,<br />
pero en este documento siempre se hablará <strong>de</strong> aplicación para evitar ambigüeda<strong>de</strong>s.<br />
2.1.3. Principales aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo<br />
En el mercado existen diferentes alternativas en lo que a aplicaciones <strong>de</strong> hojas <strong>de</strong> cálculo<br />
se refiere, y cada una <strong>de</strong> ellas con su propio formato, pero la más utilizada y extendida es<br />
Microsoft Excel [SL99], con su formato xls [Mic08b] [Mic08a], que se proporciona <strong>de</strong>ntro<br />
<strong>de</strong> la suite <strong>de</strong> aplicaciones <strong>de</strong> oficina Microsoft Office, y que se impuso en los 90 a la suite<br />
Lotus 1-2-3 <strong>de</strong> IBM y a su formato [Cor84].<br />
Como alternativa libre, <strong>de</strong>staca la suite OpenOffice.org [ope], que incluye la aplicación <strong>de</strong><br />
hojas <strong>de</strong> cálculo Calc. Esta suite ha ido ganando cada vez más mercado al permitir la utilización<br />
<strong>de</strong> otros formatos como los <strong>de</strong> Microsoft Office, y al utilizar como formato nativo Open<br />
Document Format [OAS07] [OAS10], formato estándar <strong>de</strong> la organización OASIS [oas],<br />
para garantizar que los documentos generados no que<strong>de</strong>n atados a una única aplicación.<br />
2.2. Alternativas para trabajar con hojas <strong>de</strong> cálculo<br />
En esta sección se muestran diferentes alternativas que permiten trabajar con hojas <strong>de</strong><br />
cálculo, sin necesidad <strong>de</strong> utilizar ninguna interfaz gráfica. De cada alternativa se ha analizado<br />
las siguientes características:<br />
Formatos <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo que soporta.<br />
Operaciones que permite realizar sobre los diferentes elementos <strong>de</strong>l documento <strong>de</strong><br />
hojas <strong>de</strong> cálculo.<br />
Lenguaje <strong>de</strong> programación que usa.<br />
Plataformas o sistemas operativos dón<strong>de</strong> se pue<strong>de</strong> utilizar.<br />
Tipo <strong>de</strong> licencia.<br />
Soporte que se ofrece, <strong>de</strong>cir, la ayuda a resolver fallos o problemas encontrados al utilizar<br />
la solución. Contar con un buen soporte en el caso <strong>de</strong> se produzcan problemas<br />
técnicos durante el uso <strong>de</strong> la alternativa pue<strong>de</strong> evitar un retraso elevado en su resolución.
8 2. ANTECEDENTES<br />
Actividad <strong>de</strong>l proyecto, es <strong>de</strong>cir, cada cuanto tiempo se saca una nueva versión con<br />
mejoras y resolución <strong>de</strong> bugs.<br />
Madurez <strong>de</strong> la alternativa, es <strong>de</strong>cir, el tiempo y uso que tiene. Normalmente, cuanta<br />
más madurez tiene un proyecto más estable es.<br />
Características <strong>de</strong> la documentación <strong>de</strong> uso <strong>de</strong> la alternativa.<br />
Dificultad <strong>de</strong> uso. Aunque posiblemente es la característica más subjetiva <strong>de</strong> todas, se<br />
pue<strong>de</strong> tratar <strong>de</strong> hacer una valoración lo más objetiva posible a través <strong>de</strong>l análisis <strong>de</strong>l<br />
esfuerzo que requiere realizar un ejemplo que sea lo más parecido posible en todas<br />
las alternativas o en su <strong>de</strong>fecto analizando el esfuerzo a la hora <strong>de</strong> realizar diferentes<br />
operaciones.<br />
A continuación, se <strong>de</strong>talla cada una <strong>de</strong> las alternativas analizadas.<br />
2.2.1. Estudio e implementación <strong>de</strong> los estándares<br />
Una alternativa que permite po<strong>de</strong>r trabajar con diferentes formatos <strong>de</strong> hojas <strong>de</strong> cálculo y<br />
realizar todas las operaciones que se necesiten, es la <strong>de</strong> implementar los mecanismos necesarios<br />
para modificar directamente los ficheros binarios <strong>de</strong> cada formato. Para ello es necesario<br />
el estudio completo <strong>de</strong> las especificaciones <strong>de</strong> aquellos formatos a los que se <strong>de</strong>sea dar soporte,<br />
y cumplir con los estándares marcados por dichas especificaciones <strong>de</strong> manera que se<br />
puedan crear nuevos documentos y, que a<strong>de</strong>más se puedan realizar modificaciones sobre un<br />
fichero ya creado sin invalidarlo, permitiendo así su uso en otras aplicaciones que también<br />
soporten dicho formato.<br />
Por tanto para trabajar con los principales formatos <strong>de</strong> documento <strong>de</strong> hojas <strong>de</strong> cálculo,<br />
como son los <strong>de</strong> Microsoft Excel [Mic10b] y <strong>de</strong> OpenOffice.org Calc [OAS10] necesitaríamos<br />
estudiar sus especificaciones e implementarlas. Por ejemplo, el formato <strong>de</strong> un fichero<br />
xls [Mic08b] <strong>de</strong> Microsoft Excel está dividido en diferentes registros binarios, don<strong>de</strong> algunos<br />
bytes indican el tamaño <strong>de</strong> los registros que vienen <strong>de</strong>trás, y otros registros hacen <strong>de</strong> índices<br />
<strong>de</strong>ntro <strong>de</strong>l propio fichero, por tanto es necesario conocer todos los registros que lo forman<br />
para po<strong>de</strong>r llevar a cabo la implementación <strong>de</strong> un nuevo documento y cada cambio que se<br />
realice sobre uno ya existente. Otro formato como el ods [OAS10] <strong>de</strong> OpenOffice.org Calc<br />
es un conjunto <strong>de</strong> ficheros en XML empaquetados en un sólo fichero, por tanto es necesario<br />
conocer tanto la distribución <strong>de</strong> los ficheros que intervienen como su estructura interna para<br />
po<strong>de</strong>r generar documentos válidos y permitir su modificación.<br />
En esta alternativa <strong>de</strong>staca la flexibilidad que ofrece en la mayoría <strong>de</strong> características a analizar,<br />
permitiendo elegir: el lenguaje <strong>de</strong> programación, las plataformas don<strong>de</strong> po<strong>de</strong>r utilizarse<br />
(la propia elección <strong>de</strong>l lenguaje pue<strong>de</strong> proporcionar esta característica), el tipo <strong>de</strong> licencia y
2. ANTECEDENTES 9<br />
la posibilidad <strong>de</strong> conversión entre formatos. <strong>La</strong> característica que si permanece fija es la <strong>de</strong><br />
dificultad <strong>de</strong> implementación que es muy alta.<br />
2.2.2. Microsoft Office y COM<br />
Existe una alternativa que permite utilizar la funcionalidad <strong>de</strong> las aplicaciones <strong>de</strong> Microsoft<br />
Office e incorporarla en otras aplicaciones, se llama Automation y en este apartado se<br />
va explicar en qué consiste.<br />
Automation<br />
Segun Microsoft [Mic08c] Automation (antes conocido como OLE Automation) es una<br />
tecnología que permite usar la funcionalidad <strong>de</strong> otros programas existentes e incorporarla a<br />
nuestras aplicaciones.<br />
Para po<strong>de</strong>r utilizar las funcionalida<strong>de</strong>s <strong>de</strong> otro programa se hace uso <strong>de</strong> COM que es la<br />
arquitectura software <strong>de</strong> componentes <strong>de</strong> Microsoft, que permite la comunicación entre procesos<br />
y la creación <strong>de</strong> objetos dinámicos. El programa que quiere ofrecer sus funcionalida<strong>de</strong>s<br />
para ser usadas con COM <strong>de</strong>be <strong>de</strong> generarse teniendo en cuenta la especificación <strong>de</strong> dicha arquitectura<br />
y hacer públicas las interfaces que va a permitir usar.<br />
Microsoft Excel es una aplicación que implementa COM como servicio <strong>de</strong> manera que<br />
publica sus interfaces para permitir que otras aplicaciones hagan uso <strong>de</strong> sus funcionalida<strong>de</strong>s,<br />
es través <strong>de</strong>l uso <strong>de</strong> Automation como se consigue que aplicaciones que no implementen<br />
COM puedan acce<strong>de</strong>r a los servicios <strong>de</strong> dicha arquitectura.<br />
Formas <strong>de</strong> usar un componente COM<br />
Existen principalmente 3 formas <strong>de</strong> utilizar los servicios <strong>de</strong> un componente COM <strong>de</strong>s<strong>de</strong><br />
Visual C++:<br />
1. Usar MFC.<br />
2. Usar la directiva #import.<br />
3. Usar C/C++ Automation.<br />
<strong>La</strong> primera opción, hace uso <strong>de</strong> MFC para generar un envoltorio o wrapper <strong>de</strong> clases <strong>de</strong><br />
la aplicación cliente (la que va a usar los servicios <strong>de</strong> COM) a partir <strong>de</strong> la librería <strong>de</strong> tipos<br />
<strong>de</strong> la aplicación Office a utilizar. De esta manera las clases <strong>de</strong> la aplicación cliente pasan a<br />
ser también clases <strong>de</strong> MFC y por tanto facilita su uso con Automation. Para po<strong>de</strong>r generar el<br />
envoltorio o wrapper mencionado se hace uso <strong>de</strong> una utilidad que proporciona Visual C++<br />
(disponible a partir <strong>de</strong> su versión 5.0).<br />
<strong>La</strong> segunda opción, consiste en usar la directiva #import. Al incluir dicha directiva se crean<br />
puntos <strong>de</strong> entrada a la librería que se <strong>de</strong>sea utilizar, proporcionando una opción sencilla y
10 2. ANTECEDENTES<br />
potente. El inconveniente es que la propia Microsoft [Mic08c] <strong>de</strong>saconseja su uso por problemas<br />
existentes con el control <strong>de</strong>l número <strong>de</strong> referencias en aplicaciones como Microsoft<br />
Office.<br />
<strong>La</strong> tercera y última opción, consiste en usar directamente la API <strong>de</strong> COM con C/C++,<br />
haciendo un uso a más bajo nivel <strong>de</strong> Automation <strong>de</strong>l que se realiza a través <strong>de</strong> MFC, lo que<br />
da mayor versatilidad y evita el tener que realizar envoltorios o wrappers <strong>de</strong> la clase, pero<br />
que a su vez tiene el inconveniente <strong>de</strong> ser más complejo su uso.<br />
Ejemplos <strong>de</strong> operaciones con hojas <strong>de</strong> cálculo en C/C++<br />
A continuación, se muestran algunos fragmentos <strong>de</strong> código con la i<strong>de</strong>a <strong>de</strong> ilustrar la dificultad<br />
<strong>de</strong> uso <strong>de</strong> esta alternativa a través <strong>de</strong> la tercera <strong>de</strong> las opciones mostradas en el apartado<br />
anterior, es <strong>de</strong>cir, haciendo uso <strong>de</strong> C++ Automation. Para que el código sea más sencillo, Microsoft<br />
[Mic07] en sus ejemplos hace uso <strong>de</strong> una función llamada AutoWrap que facilita el<br />
uso <strong>de</strong> Automation.<br />
// 1) Buscamos el i<strong>de</strong>ntificador <strong>de</strong>l programa Excel para COM<br />
CLSID clsid;<br />
HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);<br />
if(FAILED(hr)) {<br />
::MessageBox(NULL, "CLSIDFromProgID() failed", "Error", 0x10010);<br />
return -1;<br />
}<br />
// 2) Arrancamos el servico Excel a traves <strong>de</strong> su in<strong>de</strong>tificador<br />
IDispatch *pXlApp;<br />
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (<br />
void **)&pXlApp);<br />
if(FAILED(hr)) {<br />
::MessageBox(NULL, "Excel not registered properly", "Error", 0<br />
x10010);<br />
return -2;<br />
}<br />
Listado 2.1: Cómo cargar la aplicación Excel para ser usada través <strong>de</strong> COM<br />
{<br />
}<br />
VARIANT x;<br />
x.vt = VT_I4;<br />
x.lVal = 0; //Con 0 sera invisible (segundo plano) y con 1 se<br />
hara visible<br />
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);<br />
Listado 2.2: Cómo hacer que la carga <strong>de</strong>l servicio COM sea en segundo plano<br />
Como se pue<strong>de</strong> ver en el listado 2.1 la carga <strong>de</strong>l programa Excel como servicio COM para<br />
usarlo en otra aplicación es medianamente sencilla. Si se quiere usar dicha aplicación en
2. ANTECEDENTES 11<br />
segundo plano evitando que sea visible para el usuario, basta con asignar el valor cero a la<br />
propiedad <strong>de</strong> visibilidad como se pue<strong>de</strong> ver en el listado 2.2.<br />
En [Mic07] se pue<strong>de</strong> ver un ejemplo completo <strong>de</strong> uso don<strong>de</strong> se crea un nuevo documento<br />
<strong>de</strong> hoja <strong>de</strong> cálculo, se aña<strong>de</strong> una nueva hoja <strong>de</strong> cálculo, se selecciona la hoja activa, se<br />
selecciona un rango y a cada celda <strong>de</strong>l mismo le asigna un valor distinto, por último salva el<br />
documento y lo cierra.<br />
//El objeto don<strong>de</strong> se carga el documento es un puntero a IDispatch.<br />
{<br />
VARIANT result, fileName;<br />
fileName.vt = VT_BSTR;<br />
fileName.bstrVal = ::SysAllocString(OLESTR("c:\\fichero_prueba.<br />
xls"));<br />
VariantInit(&result);<br />
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Open", 1,<br />
fileName);<br />
pXlBook = result.pdispVal; //IDispatch *pXlBook;<br />
}<br />
Listado 2.3: Abrir un fichero Excel a través <strong>de</strong> COM<br />
//El objeto don<strong>de</strong> se carga la hoja <strong>de</strong> calculo es un puntero a IDispatch.<br />
{<br />
VARIANT result, parm;<br />
parm.vt = VT_BSTR;<br />
parm.bstrVal = ::SysAllocString(L"Hoja1");<br />
VariantInit(&result);<br />
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBook, L"Sheets", 1,<br />
parm);<br />
pXlSheet = result.pdispVal; //IDispatch *pXlSheet;<br />
}<br />
Listado 2.4: Seleccionar una hoja <strong>de</strong> cálculo a través <strong>de</strong> su nombre usando COM<br />
Otras operaciones como la <strong>de</strong> abrir un documento con formato Excel (listado 2.3) u obtener<br />
una <strong>de</strong>terminada hoja <strong>de</strong>l documento a partir <strong>de</strong> su nombre (listado 2.4) también son<br />
operaciones medianamente sencillas una vez se conoce el mecanismo <strong>de</strong> su uso. El principal<br />
problema es conocer el nombre y cómo usar <strong>de</strong>terminadas operaciones, siendo en muchas<br />
ocasiones necesario crear una macro en Excel con la operación que se quiere realizar para<br />
po<strong>de</strong>r enten<strong>de</strong>r como funciona dicha operación y po<strong>de</strong>r usarla en COM.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con cualquier formato que soporte Microsoft Excel, permitiendo<br />
a<strong>de</strong>más realizar cualquier operación que se pueda realizar con dicha aplicación.
12 2. ANTECEDENTES<br />
En realidad se soportarán todas aquellas versiones y formatos válidos para la versión <strong>de</strong><br />
Microsoft Excel usada como servicio.<br />
<strong>La</strong> necesidad <strong>de</strong> uso <strong>de</strong> la arquitectura COM impi<strong>de</strong> su uso en otras plataformas distintas<br />
<strong>de</strong> Windows. Los lenguajes que se pue<strong>de</strong>n usar para la aplicación, son todos aquellos que<br />
permitan el uso <strong>de</strong> COM.<br />
<strong>La</strong> licencia <strong>de</strong> la aplicación que implemente esta alternativa pue<strong>de</strong> ser <strong>de</strong>l tipo que se <strong>de</strong>see,<br />
pero al necesitar hacer uso <strong>de</strong>l programa Microsoft Excel siempre será necesario contar con<br />
una licencia <strong>de</strong>l mismo.<br />
<strong>La</strong> dificultad <strong>de</strong> su uso es alta, aunque a primera vista viendo los ejemplos <strong>de</strong>l apartado<br />
anterior pueda parecer un uso algo más sencillo, este se complica a la hora <strong>de</strong> buscar cómo<br />
realizar las diferentes operaciones, pues no existe un índice <strong>de</strong> todas las operaciones disponible<br />
online, y por tanto a veces es necesario buscar en ejemplos más complejos para localizar<br />
un uso concreto <strong>de</strong>l mismo y la mayoría <strong>de</strong> las veces la única posibilidad es realizar una<br />
macro en la aplicación Microsoft Excel para analizar el código generado por la misma y así<br />
usarlo <strong>de</strong> guía para conocer cómo realizar la operación.<br />
Esta alternativa al hacer uso <strong>de</strong> la tecnología <strong>de</strong> componentes <strong>de</strong> Windows y existir multitud<br />
<strong>de</strong> aplicaciones que hacen uso <strong>de</strong> ella tiene como resultado una alternativa con una<br />
madurez y actividad muy alta. A<strong>de</strong>más, el soporte también es muy alto.<br />
2.2.3. OpenOffice.org y UNO<br />
Existe una alternativa que permite utilizar la funcionalidad <strong>de</strong> las aplicaciones <strong>de</strong> OpenOffice.org<br />
e incorporarla en otras aplicaciones, al igual que ocurre con COM y Microsoft Office<br />
como se ha visto en el apartado anterior, esta se llama UNO y en este apartado se va explicar<br />
en qué consiste.<br />
UNO Universal Network Objects<br />
UNO [Ora10] es la base <strong>de</strong> la tecnología <strong>de</strong> componentes <strong>de</strong> OpenOffice.org que permite<br />
utilizar objetos entre diferentes plataformas y lenguajes a través <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> una serie<br />
<strong>de</strong> interfaces que <strong>de</strong>ben <strong>de</strong> ser implementadas.<br />
UNO tiene soporte para la siguientes plataformas: GNU/Linux, Solaris, Windows, Power<br />
PC, FreeBSD, MacOS. Y también permite usarse con los lenguajes: Java, C++, OpenOffice.org<br />
Basic, .Net, Python.<br />
<strong>La</strong> suite <strong>de</strong> ofimática OpenOffice.org implementa a su vez las interfaces <strong>de</strong> UNO necesarias<br />
para permitir incorporar las funcionalida<strong>de</strong>s <strong>de</strong> sus aplicaciones en otras aplicaciones.
2. ANTECEDENTES 13<br />
Formas <strong>de</strong> conectar a OpenOffice.org con UNO<br />
Existen principalmente 2 formas <strong>de</strong> utilizar los servicios <strong>de</strong> OpenOffice.org a través <strong>de</strong><br />
UNO:<br />
1. Usar una comunicación local a través <strong>de</strong> una tubería o pipe.<br />
2. Usar una comunicación remota a través <strong>de</strong> sockets.<br />
soffice -headless -accept="socket,port=8100;urp;"<br />
Listado 2.5: Arracar OpenOffice.org en modo servicio escuchando en un socket<br />
<strong>La</strong> primera opción requiere que el ejecutable soffice sea arrancado con unas opciones<br />
<strong>de</strong>terminadas para que se inicie en modo servicio escuchando en un puerto. En el listado 2.5<br />
se muestra como arrancar el proceso <strong>de</strong> OpenOffice.org como servicio para que se que<strong>de</strong><br />
a la escucha <strong>de</strong> peticiones por socket en el puerto 8100. Esto permite po<strong>de</strong>r usar toda la<br />
funcionalidad <strong>de</strong> OpenOffice.org Calc, y <strong>de</strong>l resto <strong>de</strong> aplicaciones <strong>de</strong> la suite ofimática, sin<br />
necesidad <strong>de</strong> tener instalado el programa en la misma máquina don<strong>de</strong> se va a usar, pues<br />
proporciona una comunicación remota a través <strong>de</strong> un puente o bridge <strong>de</strong> UNO.<br />
soffice -headless -accept=pipe,name=uno2;urp;"<br />
Listado 2.6: Arracar OpenOffice.org en modo servicio escuchando en una tubería o pipe<br />
<strong>La</strong> segunda opción requiere que el ejecutable soffice sea arrancando con la opciones <strong>de</strong><br />
servicio escuchando en una tubería o pipe con un <strong>de</strong>terminado i<strong>de</strong>ntificador. Esto permite la<br />
comunicación con otros procesos en local a través <strong>de</strong> UNO para hacer uso <strong>de</strong> la funcionalidad<br />
<strong>de</strong> OpenOffice.org. En el listado 2.6 se muestra como arrancar el proceso OpenOffice.org<br />
como servicio para que escuche en una tubería o pipe <strong>de</strong> proceso i<strong>de</strong>ntificada con el nombre<br />
«uno2».<br />
String sConnect =<br />
"uno:socket,host=localhost,port=8100;urp;StarOffice.ComponentContext";<br />
Listado 2.7: Ca<strong>de</strong>na <strong>de</strong> conexión para conectar con un servicio a través <strong>de</strong> socket<br />
Una vez se ha arrancado el servicio <strong>de</strong> OpenOffice.org para conectar con él <strong>de</strong>s<strong>de</strong> otra<br />
aplicación, en ambas opciones, es necesario resolver la ca<strong>de</strong>na <strong>de</strong> conexión o URL correspondiente<br />
en cada caso (listado 2.7 y listado 2.8) a través <strong>de</strong>l objeto XUnoUrlResolver, que<br />
<strong>de</strong>volverá el objeto XComponentContext <strong>de</strong>l servicio remoto a través <strong>de</strong>l cuál se pue<strong>de</strong>n<br />
obtener el resto <strong>de</strong> objetos necesarios para trabajar con OpenOffice.org Calc.
14 2. ANTECEDENTES<br />
String sConnect = "uno:pipe,name=uno2;urp;StarOffice.ComponentContext";<br />
Listado 2.8: Ca<strong>de</strong>na <strong>de</strong> conexión para conectar con un servicio a través <strong>de</strong> una tubería o pipe<br />
Método bootstrap<br />
En el SDK <strong>de</strong> OpenOffice.org se proporciona la clase Bootstrap con un método estático<br />
llamado bootstrap que permite en una sola llamada ejecutar el servicio <strong>de</strong> OpenOffice.org<br />
y recuperar el objeto XComponentContext. Esto facilita mucho la conexión con el servicio,<br />
pues proporciona directamente el objeto necesario para trabajar con OpenOffice.org Calc<br />
ocultando todos los pasos necesarios para establecer la comunicación. Este método por <strong>de</strong>ntro<br />
realiza los siguientes pasos:<br />
1. Localiza el directorio don<strong>de</strong> se encuentra el ejecutable soffice (según el sistema don<strong>de</strong><br />
se ejecuta sea GNU/Linux o Windows usa distintos mecanismos).<br />
2. Ejecuta el fichero soffice con los parámetros necesarios para que actúe como servicio<br />
y escuche en una tubería o pipe.<br />
3. Conecta con el servicio a través <strong>de</strong> la tubería abierta.<br />
4. Recupera el XComponentContext y lo <strong>de</strong>vuelve.<br />
Este método sólo pue<strong>de</strong> ser utilizado cuando la instalación <strong>de</strong> OpenOffice.org está en la<br />
misma máquina que la clase que va a usar el método bootstrap.<br />
Ejemplo <strong>de</strong> operaciones con hojas <strong>de</strong> cálculo usando UNO<br />
En este apartado se va a explicar un ejemplo completo <strong>de</strong> método que hace uso <strong>de</strong> Calc<br />
para crear un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo al que le aña<strong>de</strong> una nueva hoja <strong>de</strong> cálculo<br />
y asigna valores a dos celdas, para finalmente guardar el documento con formato xls <strong>de</strong><br />
Excel. El objetivo <strong>de</strong> este ejemplo es el <strong>de</strong> ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong> la<br />
alternativa.<br />
XComponentContext xContext = Bootstrap.bootstrap();<br />
XMultiComponentFactory xServiceManger = xContext.getServiceManager();<br />
Object <strong>de</strong>sktop =<br />
xServiceManger.createInstanceWithContext("com.sun.star.frame.Desktop",<br />
xContext);<br />
XComponentLoa<strong>de</strong>r xComponentLoa<strong>de</strong>r =<br />
(XComponentLoa<strong>de</strong>r) UnoRuntime.queryInterface(XComponentLoa<strong>de</strong>r.class,<br />
<strong>de</strong>sktop);<br />
Listado 2.9: Ejemplo uso UNO parte 1: Cómo obtener el objeto remoto XComponentLoa<strong>de</strong>r
2. ANTECEDENTES 15<br />
El primer paso (listado 2.9) es obtener el objeto remoto XComponentLoa<strong>de</strong>r, para ello<br />
se utiliza el método bootstrap comentado en el apartado anterior, y mediante el XComponentContext<br />
recuperado se crear una instancia remota <strong>de</strong>l tipo com.sun.star.frame.Desktop<br />
que permite hacer un casting a la clase <strong>de</strong>l objeto esperado. Los castings en el entorno UNO<br />
se realizan a través <strong>de</strong> una consulta al runtime que comprueba primero que el objeto pue<strong>de</strong><br />
realizar el casting a una <strong>de</strong>terminada clase y a<strong>de</strong>más que el enlace al objeto remoto sigue<br />
activo.<br />
PropertyValue[] loadProps = new PropertyValue[1];<br />
loadProps[0] = new PropertyValue();<br />
loadProps[0].Name = "Hid<strong>de</strong>n";<br />
loadProps[0].Value = new Boolean(true);<br />
XComponent xSpreadsheetComponent =<br />
xComponentLoa<strong>de</strong>r.loadComponentFromURL("private:factory/scalc", "_blank",<br />
0, loadProps);<br />
XSpreadsheetDocument xSpreadsheetDocument =<br />
(XSpreadsheetDocument) UnoRuntime.queryInterface(<br />
XSpreadsheetDocument.class, xSpreadsheetComponent);<br />
Listado 2.10: Ejemplo uso UNO parte 2: Cómo crear un nuevo documento <strong>de</strong> hojas <strong>de</strong><br />
cálculo<br />
El segundo paso (listado 2.10) es cargar un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo haciendo<br />
uso <strong>de</strong>l objeto remoto XComponentLoa<strong>de</strong>r, para ello se le pasa una lista <strong>de</strong> propieda<strong>de</strong>s<br />
con la propiedad que hace que se realice la operación <strong>de</strong> creación en segundo plano, y por<br />
tanto <strong>de</strong> manera transparente al usuario. Como resultado <strong>de</strong> la creación obtenemos un objeto<br />
XSpreadsheetDocument.<br />
XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();<br />
xSpreadsheets.insertNewByName("Hoja_prueba", (short) 0);<br />
Object sheet = xSpreadsheets.getByName("Hoja_prueba");<br />
XSpreadsheet xSpreadsheet =<br />
(XSpreadsheet) UnoRuntime.queryInterface(XSpreadsheet.class, sheet);<br />
Listado 2.11: Ejemplo uso UNO parte 3: Añadir una nueva hoja <strong>de</strong> cálculo al documento<br />
El tercer paso (listado 2.11) consiste en añadir una nueva hoja <strong>de</strong> cálculo y para ello es<br />
necesario recuperar el objeto XSpreadsheets que representa la lista <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong>l<br />
documento. Puesto que el método que aña<strong>de</strong> hojas <strong>de</strong> cálculo no <strong>de</strong>vuelve nada, para po<strong>de</strong>r<br />
operar <strong>de</strong>spués con la hoja creada, es necesario recuperarla antes a través <strong>de</strong> su nombre. Al<br />
final como resultado obtenemos un objeto XSpreadsheet.
16 2. ANTECEDENTES<br />
XCell xCell = xSpreadsheet.getCellByPosition(0, 0); //celda A1<br />
xCell.setValue(16.6);<br />
xCell = xSpreadsheet.getCellByPosition(1, 1); //celda B2<br />
xCell.setValue(199);<br />
Listado 2.12: Ejemplo uso UNO parte 4: Insertar valores a celdas<br />
El siguiente paso (listado 2.12) consiste en insertar valores a dos celdas <strong>de</strong>l objeto XSpreadsheet<br />
recuperado en el paso anterior. Para ello es necesario primero obtener el objeto<br />
XCell, que se recupera a través <strong>de</strong> la posición que ocupa en la hoja <strong>de</strong> cálculo, y <strong>de</strong>spués<br />
usar el método que permite asignarle un valor.<br />
XStorable xStorable =<br />
(XStorable)UnoRuntime.queryInterface(XStorable.class,<br />
xSpreadsheetComponent);<br />
PropertyValue[] storeProps = new PropertyValue[1];<br />
storeProps[0] = new PropertyValue();<br />
storeProps[0].Name = "FilterName";<br />
storeProps[0].Value = "MS Excel 97";<br />
File outputFile = new File("salida.xls");<br />
xStorable.storeAsURL("file:///"+outputFile.getAbsolutePath(), storeProps)<br />
;<br />
Listado 2.13: Ejemplo uso UNO parte 5: Guardar un documento con formato xls<br />
El último paso (listado 2.13) consiste en salvar el documento y las modificaciones realizadas<br />
en él en un fichero con formato <strong>de</strong> Microsoft Excel concretamente el formato xls. Para<br />
ello es necesario obtener a partir <strong>de</strong>l XComponent, que representa el documento cargado en<br />
memoria, un objeto XStorable que permite realizar el salvado a fichero. Como se <strong>de</strong>sea guardar<br />
el documento con un formato distinto al nativo <strong>de</strong> la aplicación OpenOffice.org Calc, es<br />
necesario <strong>de</strong>finir una lista <strong>de</strong> propieda<strong>de</strong>s con un filtro que indique al método <strong>de</strong> salvado en<br />
qué formato se <strong>de</strong>sea guardar el documento.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con cualquier formato que soporte OpenOffice.org Calc<br />
que incluye los formatos <strong>de</strong> Microsoft Excel, permitiendo realizar cualquier operación permitida<br />
en dicha aplicación, incluyendo la conversión entre los formatos permitidos y la exportación<br />
a PDF.<br />
Como ya se comentó en apartados anteriores UNO permite el uso <strong>de</strong> diferentes lenguajes<br />
y plataformas.
2. ANTECEDENTES 17<br />
<strong>La</strong> licencia <strong>de</strong> la aplicación que implemente esta alternativa pue<strong>de</strong> ser libre y seguir haciendo<br />
uso <strong>de</strong> OpenOffice.org sin necesidad <strong>de</strong> tener ningún tipo <strong>de</strong> licencia.<br />
<strong>La</strong> dificultad <strong>de</strong> su uso <strong>de</strong> esta alternativa es alta <strong>de</strong>bido a la compleja jerarquía <strong>de</strong> objetos<br />
que <strong>de</strong>riva en una gran cantidad <strong>de</strong> interfaces que siempre <strong>de</strong>be ser recuperadas en tiempo<br />
<strong>de</strong> ejecución lo que obliga a conocer dicha estructura previamente.<br />
<strong>La</strong> documentación para usar UNO es completa y existen gran cantidad <strong>de</strong> ejemplos, sobre<br />
todo para el <strong>de</strong>sarrollo en Java.<br />
Esta alternativa hace uso <strong>de</strong> la tecnología <strong>de</strong> componentes diseñada para usarse directamente<br />
con la suite ofimática OpenOffice.org y forma parte <strong>de</strong> ella, eso unido al uso extendido<br />
<strong>de</strong> esta suite <strong>de</strong>s<strong>de</strong> hace varios años y a la salida con frecuencia <strong>de</strong> versiones da como resultado<br />
una alternativa con una madurez y actividad muy alta. A<strong>de</strong>más, el soporte ofrecido<br />
tanto por la comunidad como por los <strong>de</strong>sarrolladores también es muy alto.<br />
2.2.4. Apache POI<br />
Existe un grupo <strong>de</strong> proyectos con el nombre <strong>de</strong> Apache POI [Foua] que proporcionan<br />
una serie <strong>de</strong> APIs en Java para trabajar con los diferentes formatos <strong>de</strong> Microsoft Office.<br />
Concretamente la API que proporciona el soporte para acce<strong>de</strong>r a los formatos <strong>de</strong> Microsoft<br />
Excel, es <strong>de</strong>cir, a los documentos <strong>de</strong> hojas <strong>de</strong> cálculo, es la compuesta por los proyectos<br />
POI-HSSF and POI-XSSF [Foud].<br />
Estas APIs están escritas totalmente en Java e implementan los estándares <strong>de</strong> los formatos<br />
que soportan que son xls y xlsx, es <strong>de</strong>cir, llevan a cabo lo mencionado en la primera <strong>de</strong> las<br />
alternativas y por tanto no necesitan hacer uso <strong>de</strong> otras aplicaciones como si ocurre en las<br />
dos alternativas anteriores.<br />
Ejemplo <strong>de</strong> operaciones con hojas <strong>de</strong> cálculo usando Apache POI<br />
En este apartado se va a explicar un ejemplo completo <strong>de</strong> método que hace uso <strong>de</strong> la<br />
librería Apache POI para crear un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo al que le aña<strong>de</strong> una<br />
nueva hoja <strong>de</strong> cálculo y le asigna valores a dos celdas, para finalmente guardar el documento<br />
con formato xls <strong>de</strong> Excel.<br />
En el listado 2.14 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar las operaciones sobre un<br />
nuevo documento <strong>de</strong> hojas cálculo. Los pasos seguidos han sido los siguientes:<br />
1. Se ha creado un nuevo documento xls a partir <strong>de</strong> un objeto HSSFWorkbook.<br />
2. Se ha añadido al documento una nueva hoja <strong>de</strong> cálculo, usando el método correspondiente<br />
para ello createSheet. Este método nos <strong>de</strong>vuelve el objeto HSSFSheet que<br />
representa la hoja creada.
18 2. ANTECEDENTES<br />
HSSFWorkbook wb = new HSSFWorkbook();<br />
HSSFSheet sheet = wb.createSheet("Hoja_prueba");<br />
HSSFRow row0 = sheet.createRow((short)0);<br />
row0.createCell(0).setCellValue(16.6); //Celda A1<br />
HSSFRow row1 = sheet.createRow((short)1);<br />
row1.createCell(1).setCellValue(199); //Celda B2<br />
FileOutputStream fileOut = new FileOutputStream("workbook.xls");<br />
wb.write(fileOut);<br />
fileOut.close();<br />
Listado 2.14: Ejemplo uso Apache POI<br />
3. Para po<strong>de</strong>r asignar un valor a una celda, antes es necesario crear un objeto Row que<br />
representa la fila.<br />
4. Una vez se tiene el objeto Row simplemente se usa el método para asignarle un valor<br />
a la celda indicando el índice <strong>de</strong> la columna.<br />
5. El último paso consiste en guardar el contenido <strong>de</strong>l documento, para ello se hace uso<br />
<strong>de</strong>l método write proporcionado, al que es necesario pasarle un objeto FileOutputStream<br />
con el nombre que se <strong>de</strong>sea dar al fichero.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con los formatos xls y xlsx <strong>de</strong> Microsoft Excel, permitiendo<br />
realizar la mayoría <strong>de</strong> las operaciones con las siguientes limitaciones:<br />
No permite crear gráficos, aunque si el fichero con el que trabaja ya tiene alguno creado<br />
con otro programa, se pue<strong>de</strong>n modificar las celdas que son usadas como datos <strong>de</strong> dicho<br />
gráfico.<br />
No permite crear macros ni modificarlas, pero si el fichero tiene macros las mantiene.<br />
No permite crear tablas dinámicas, en inglés pivot tables, pero las mantiene si el documento<br />
las incluye.<br />
El lenguaje <strong>de</strong> programación usado es Java, y al estar la librería escrita completamente<br />
en dicho lenguaje, hace que la solución sea multiplataforma, pudiendo usarse en cualquier<br />
sistema que tenga una implementación <strong>de</strong> máquina virtual <strong>de</strong> Java.<br />
<strong>La</strong> librería tiene una licencia Apache 2.0 por tanto la aplicación que implemente esta<br />
alternativa pue<strong>de</strong> ser libre o con licencia privativa.
2. ANTECEDENTES 19<br />
<strong>La</strong> dificultad <strong>de</strong> su uso es más sencilla que otras alternativas al no necesitar conectar con<br />
otras aplicaciones para operar con hojas <strong>de</strong> cálculo si no que se usan directamente los objetos<br />
que representan cada elemento <strong>de</strong> un documento <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Apache POI cuenta con una documentación en línea completa y con gran cantidad <strong>de</strong><br />
ejemplos que muestran cómo utilizar la mayoría <strong>de</strong> las funcionalida<strong>de</strong>s que ofrece.<br />
Esta alternativa lleva en usándose en diferentes proyectos tanto libres como privativos<br />
<strong>de</strong>s<strong>de</strong> hace varios años, esto unido a la publicación frecuente <strong>de</strong> nuevas versiones y al soporte<br />
proporcionado por Apache y su comunidad da como resultado una solución con una<br />
actividad, soporte y madurez muy altas.<br />
2.2.5. Spreadsheet::ParseExcel<br />
Spreadsheet::ParseExcel [Tak] es un módulo en Perl que permite extraer información <strong>de</strong><br />
ficheros <strong>de</strong> Excel en las versiones 95 y 97-2000 a través <strong>de</strong> la implementación <strong>de</strong> los estándares<br />
<strong>de</strong> dichos formatos. No permite insertar información en los documentos <strong>de</strong> hojas<br />
<strong>de</strong> cálculo y tampoco permite extraer fórmulas generadas con el módulo <strong>de</strong> Perl Spreadsheet::WriteExcel.<br />
Ejemplo <strong>de</strong> código usando ParseExcel<br />
En este apartado se muestra un ejemplo [Tak], extraído <strong>de</strong> la documentación <strong>de</strong>l módulo,<br />
con el objetivo <strong>de</strong> ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong>l mismo. En el ejemplo se recorren<br />
las celdas <strong>de</strong> un documento y se imprimen .<br />
use strict;<br />
use Spreadsheet::ParseExcel;<br />
my $oBook =<br />
Spreadsheet::ParseExcel::Workbook->Parse(’Excel/Test97.xls’);<br />
my($iR, $iC, $oWkS, $oWkC);<br />
foreach my $oWkS (@{$oBook->{Worksheet}}) {<br />
print "--------- SHEET:", $oWkS->{Name}, "\n";<br />
for(my $iR = $oWkS->{MinRow} ;<br />
<strong>de</strong>fined $oWkS->{MaxRow} && $iR {MaxRow} ; $iR++) {<br />
for(my $iC = $oWkS->{MinCol} ;<br />
<strong>de</strong>fined $oWkS->{MaxCol} && $iC {MaxCol} ; $iC++) {<br />
$oWkC = $oWkS->{Cells}[$iR][$iC];<br />
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);<br />
}<br />
}<br />
}<br />
Listado 2.15: Ejemplo uso Spreadsheet::ParseExcel<br />
En el listado 2.15 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar la operación <strong>de</strong> lectura <strong>de</strong><br />
las celdas <strong>de</strong> un documento.
20 2. ANTECEDENTES<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa sólo permite trabajar con las versiones antiguas <strong>de</strong>l formato xls, y solamente<br />
para la lectura <strong>de</strong> la información, es <strong>de</strong>cir, no permite su modificación.<br />
El lenguaje <strong>de</strong> programación usado es Perl, y al estar el módulo escrito completamente en<br />
dicho lenguaje, el módulo es multiplataforma, permitiendo su uso en cualquier sistema que<br />
tenga una implementación <strong>de</strong>l intérprete <strong>de</strong> Perl.<br />
<strong>La</strong> librería tiene una licencia GNU GPL y por tanto la aplicación que implemente esta<br />
alternativa <strong>de</strong>be ser libre y usar el mismo tipo <strong>de</strong> licencia.<br />
<strong>La</strong> dificultad <strong>de</strong> esta alternativa es alta al no disponer <strong>de</strong> una documentación completa.<br />
Spreadsheet::ParseExcel lleva en <strong>de</strong>sarrollo <strong>de</strong>s<strong>de</strong> el 2000 sacando versiones con frecuencia,y<br />
ofreciendo soporte a través <strong>de</strong> un grupo creado en Google, por tanto este módulo tiene<br />
una madurez y actividad altas, con un soporte medio.<br />
2.2.6. Spreadsheet::Read<br />
Spreadsheet::Read [Bra] es un módulo en Perl que permite extraer los datos <strong>de</strong> diferentes<br />
formatos <strong>de</strong> documentos <strong>de</strong> hoja <strong>de</strong> cálculo como los formatos sxc y ods <strong>de</strong> OpenOffice.org,<br />
xls y xlsx <strong>de</strong> Microsoft Excel, CSV y otros.<br />
Este módulo en lugar <strong>de</strong> implementar los diferentes formatos, hace uso <strong>de</strong> diferentes módulos<br />
para obtener la información <strong>de</strong> cada tipo <strong>de</strong> documento <strong>de</strong> hoja <strong>de</strong> cálculo, ofreciendo<br />
un mecanismo homogéneo <strong>de</strong> acceso a los datos <strong>de</strong> un documento in<strong>de</strong>pendientemente <strong>de</strong> su<br />
formato.<br />
Ejemplo <strong>de</strong> código usando Read<br />
En este apartado se muestra un ejemplo [Bra], extraído <strong>de</strong> la documentación <strong>de</strong>l módulo,<br />
en el que se abre un documento <strong>de</strong> formato xls y se obtiene el valor <strong>de</strong> una celda. A<strong>de</strong>más, se<br />
muestra un ejemplo <strong>de</strong> la estructura usada para almacenar la información <strong>de</strong> un documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo. El objetivo principal <strong>de</strong> mostrar el código usado es el <strong>de</strong> ilustrar el nivel<br />
<strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong>l componente.<br />
use Spreadsheet::Read;<br />
my $ref = ReadData ("test.xls");<br />
my $a3 = $ref->[1]{A1}, "\n";<br />
Listado 2.16: Ejemplo uso Spreadsheet::Read
2. ANTECEDENTES 21<br />
En el listado 2.16 se pue<strong>de</strong> ver el código resultante para abrir un documento <strong>de</strong> hojas <strong>de</strong><br />
cálculo que tiene formato xls, y <strong>de</strong>spués obtener el valor <strong>de</strong> la celda A1 <strong>de</strong> la primera hoja<br />
<strong>de</strong> cálculo.<br />
$ref =<br />
[<br />
# Elemento 0: contiene la informacion general <strong>de</strong>l documento<br />
{ sheets => 2,<br />
sheet => {<br />
"Sheet 1" => 1,<br />
"Sheet 2" => 2,<br />
},<br />
type => "xls",<br />
parser => "Spreadsheet::ParseExcel",<br />
version => 0.26,<br />
},<br />
# Elemento 1: contiene la informacion <strong>de</strong> la primera hoja<br />
{ label => "Sheet 1",<br />
maxrow => 2,<br />
maxcol => 4,<br />
cell => [ un<strong>de</strong>f,<br />
[ un<strong>de</strong>f, 1 ],<br />
[ un<strong>de</strong>f, un<strong>de</strong>f, un<strong>de</strong>f, un<strong>de</strong>f, un<strong>de</strong>f, "Nugget" ],<br />
],<br />
A1 => 1,<br />
B5 => "Nugget",<br />
},<br />
# Elemento 2: contiene la informacion <strong>de</strong> la segunda hoja<br />
{ label => "Sheet 2",<br />
:<br />
: }<br />
Listado 2.17: Ejemplo <strong>de</strong> la estructura <strong>de</strong> datos <strong>de</strong> un documento <strong>de</strong> Spreadsheet::Read<br />
En el listado 2.17 obtenido <strong>de</strong> la documentación <strong>de</strong>l módulo [Bra] se pue<strong>de</strong> ver como toda<br />
la información recuperada al leer un documento <strong>de</strong> hojas <strong>de</strong> cálculo se almacena en array<br />
don<strong>de</strong> el primer elemento contiene los datos referentes al documento completo, tales como el<br />
número y nombre <strong>de</strong> las hojas que contiene, el tipo <strong>de</strong> documento y el parser utilizado junto<br />
con su versión; el resto <strong>de</strong> elementos contienen los datos <strong>de</strong> cada una <strong>de</strong> las hojas <strong>de</strong> cálculo<br />
(nombre, número <strong>de</strong> filas, número <strong>de</strong> columnas, valores <strong>de</strong> las celdas). Como el módulo no<br />
está programado con orientación a objetos, basta con conocer las estructuras que contienen<br />
la información para trabajar con ellas.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con múltiples formatos <strong>de</strong> hojas <strong>de</strong> cálculo pero solamente
22 2. ANTECEDENTES<br />
para la lectura <strong>de</strong> la información como el nombre <strong>de</strong>l módulo indica, por lo tanto no permite<br />
modificación ni creación <strong>de</strong> documentos.<br />
El lenguaje <strong>de</strong> programación usado es Perl, y al estar el módulo escrito completamente en<br />
dicho lenguaje, incluyendo los módulos que utiliza, es multiplataforma, pudiendo usarse en<br />
cualquier sistema que tenga una implementación <strong>de</strong>l intérprete <strong>de</strong> Perl.<br />
<strong>La</strong> librería tiene una licencia GNU GPL y la aplicación que implemente esta alternativa<br />
<strong>de</strong>be ser libre y usar el mismo tipo <strong>de</strong> licencia.<br />
<strong>La</strong> dificultad <strong>de</strong> uso es sencilla al disponer <strong>de</strong> una documentación don<strong>de</strong> se muestran las<br />
estructuras completas en las que se carga la información a utilizar, como ya se ha ilustrado<br />
en el apartado anterior, y las funciones principales <strong>de</strong> uso. En este caso como el módulo no<br />
está programado con orientación a objeto, basta con conocer las estructuras que contienen la<br />
información para trabajar con ellas.<br />
Spreadsheet::Read lleva en <strong>de</strong>sarrollo <strong>de</strong>s<strong>de</strong> el 2005 sacando versiones con frecuencia pero<br />
no ofrece soporte directamente a través <strong>de</strong> algún canal directo salvo la gestión <strong>de</strong> bugs que<br />
ofrece CPAN [CPA] por <strong>de</strong>fecto, lo que hace que tenga una madurez y actividad altas, sin<br />
soporte directo, puesto que no existe ninguna actividad en el sistema ofrecido por CPAN.<br />
2.2.7. Spreadsheet::WriteExcel<br />
Spreadsheet::WriteExcel [McN] es un módulo en Perl que permite crear nuevos ficheros<br />
<strong>de</strong> Excel en las versiones 97-2000, 2002, 2003 y 2007 a través <strong>de</strong> la implementación <strong>de</strong> los<br />
estándares <strong>de</strong> dichos formatos. No tiene soporte para modificar ficheros Excel generados con<br />
Microsoft Excel, y en caso <strong>de</strong> modificarlo todos aquellos elementos como macros, gráficos<br />
y otras funcionalida<strong>de</strong>s que no se soportan se per<strong>de</strong>rán.<br />
Ejemplo <strong>de</strong> código usando WriteExcel<br />
En este apartado se muestra un ejemplo que adapta el primer ejemplo [McN] <strong>de</strong> la documentación<br />
para que se realicen las mismas operaciones que se han hecho con otras alternativas.<br />
El ejemplo consiste en crear un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo al que le aña<strong>de</strong><br />
una nueva hoja <strong>de</strong> cálculo y le asigna valores a dos celdas. El objetivo <strong>de</strong> este ejemplo es el<br />
<strong>de</strong> ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong> la alternativa.<br />
En el listado 2.18 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar la creación <strong>de</strong>l documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo, al que se le aña<strong>de</strong> una nueva hoja <strong>de</strong> cálculo y se asignan valores a dos<br />
<strong>de</strong> sus celdas.
2. ANTECEDENTES 23<br />
use Spreadsheet::WriteExcel;<br />
my $workbook = Spreadsheet::WriteExcel->new(’workbook.xls’);<br />
$worksheet = $workbook->add_worksheet(’Hoja_prueba’, 1);<br />
$worksheet->write(’A1’, 16.6);<br />
$worksheet->write(’B2’, 199);<br />
$workbook->close();<br />
Listado 2.18: Ejemplo uso Spreadsheet::WriteExcel<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con las diferentes versiones <strong>de</strong>l formato xls, para su creación,<br />
pero la modificación <strong>de</strong> ficheros generados con Microsoft Excel pue<strong>de</strong> provocar pérdida<br />
<strong>de</strong> diferentes funcionalida<strong>de</strong>s.<br />
El lenguaje <strong>de</strong> programación usado es Perl, y al estar el módulo escrito completamente<br />
en dicho lenguaje es multiplataforma, pudiendo usarse en cualquier sistema que tenga una<br />
implementación <strong>de</strong>l intérprete <strong>de</strong> Perl.<br />
<strong>La</strong> librería tiene una licencia GNU GPL y la aplicación que implemente esta alternativa<br />
<strong>de</strong>be ser libre y usar el mismo tipo <strong>de</strong> licencia.<br />
<strong>La</strong> dificultad es sencilla pues los métodos son bastantes explícitos y a<strong>de</strong>más se proporciona<br />
una documentación con el listado <strong>de</strong> todos los métodos disponibles.<br />
Spreadsheet::WriteExcel lleva en <strong>de</strong>sarrollo <strong>de</strong>s<strong>de</strong> hace más <strong>de</strong> diez años, sacando versiones<br />
con cierta frecuencia,y ofreciendo soporte a través <strong>de</strong> un grupo creado en Google, por<br />
tanto este módulo tiene una madurez y un soporte altos, y su actividad es media, al haberse<br />
reducido en el último año los cambios realizados en el módulo.<br />
2.2.8. OpenOffice::OODoc<br />
OpenOffice::OODoc [Gou] es un módulo en Perl que permite trabajar con documentos en<br />
formato Open Document [OAS07], ofreciendo las funcionalida<strong>de</strong>s necesaria para crear nuevos<br />
documentos y modificar documentos ya existentes, siendo compatible con documentos<br />
<strong>de</strong> texto, documentos <strong>de</strong> hojas <strong>de</strong> cálculo y documentos <strong>de</strong> presentación.<br />
En la documentación <strong>de</strong> OpenOffice::OODoc, no se recomienda usar dicho módulo para<br />
crear tablas complejas como las usadas para representar una hoja <strong>de</strong> cálculo. En su lugar se<br />
aconseja usar otras herramientas que también trabajen con Open Document y que permitan<br />
crear este tipo <strong>de</strong> tablas.
24 2. ANTECEDENTES<br />
Ejemplo <strong>de</strong> código usando OODoc<br />
En este apartado <strong>de</strong>bido a la limitación <strong>de</strong>l módulo para crear hojas <strong>de</strong> cálculo, se ha<br />
realizado un ejemplo haciendo uso <strong>de</strong> los ejemplos mostrados en la documentación <strong>de</strong>l módulo<br />
[Gou] que consiste en crear un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo y asignarle a la<br />
primera hoja <strong>de</strong> cálculo valores a dos <strong>de</strong> sus celdas. El objetivo <strong>de</strong> este ejemplo es el <strong>de</strong><br />
ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong> la alternativa.<br />
use OpenOffice::OODoc;<br />
my $workbook = odfContainer("workbook.ods", create => ’spreadsheet’);<br />
my $worksheet = $workbook->expandTable(0, 5, 5);<br />
$workbook->cellValue($worksheet,0,0,16.6);<br />
$workbook->cellValue($worksheet,1,1,199);<br />
$workbook->save;<br />
Listado 2.19: Ejemplo uso OpenOffice::OODoc<br />
En el listado 2.19 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar la creación <strong>de</strong>l documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo, el cuál por <strong>de</strong>fecto es creado con una única hoja <strong>de</strong> cálculo que contiene<br />
una celda. Para po<strong>de</strong>r aumentar el número <strong>de</strong> celdas, es necesario hacer uso <strong>de</strong>l método<br />
explandTable, en el ejemplo se aña<strong>de</strong>n varias celdas, y una vez añadidas se asignan valores<br />
a dos <strong>de</strong> ellas.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con el formato Open Document proporcionando las funcionalida<strong>de</strong>s<br />
necesarias para la creación y modificación <strong>de</strong> los diferentes tipos <strong>de</strong> ficheros,<br />
odt para documentos <strong>de</strong> texto, ods para documentos <strong>de</strong> hojas <strong>de</strong> cálculo y odp para documentos<br />
<strong>de</strong> presentaciones; con una importante limitación, puesto que no se recomienda usar<br />
sus funciones para crear nuevas hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un documento.<br />
El lenguaje <strong>de</strong> programación usado es Perl, y al estar el módulo escrito completamente<br />
en dicho lenguaje hace que la alternativa sea multiplataforma, pudiéndose usar en cualquier<br />
sistema que tenga una implementación <strong>de</strong>l intérprete <strong>de</strong> Perl.<br />
<strong>La</strong> librería tiene una licencia GNU LGPL y por tanto la aplicación que implemente esta<br />
alternativa pue<strong>de</strong> ser libre o usar una licencia privativa.<br />
<strong>La</strong> dificultad es alta puesto que al tratar <strong>de</strong> manejar <strong>de</strong> manera uniforme todos los tipos<br />
<strong>de</strong> documentos <strong>de</strong>l formato Open Document, hay conceptos que <strong>de</strong>saparecen, por ejemplo<br />
no existe directamente el concepto <strong>de</strong> hojas <strong>de</strong> cálculo si no que se representa a través <strong>de</strong>l
2. ANTECEDENTES 25<br />
concepto <strong>de</strong> tabla, y los diferentes tipos <strong>de</strong> tablas se tratan igual, ya sea una simple tabla con<br />
texto que se vaya a insertar en un documento <strong>de</strong> texto o una tabla compleja que representa una<br />
hoja <strong>de</strong> cálculo; sin embargo, hay acciones que si requieren realizar operaciones adicionales<br />
cuando se trata con tablas que representan hojas <strong>de</strong> cálculo. A<strong>de</strong>más <strong>de</strong> todo lo anterior, la<br />
documentación tien<strong>de</strong> a hablar <strong>de</strong> los diferentes elementos que existen sin hacer divisiones<br />
<strong>de</strong> lo permitido para cada uno <strong>de</strong> los tipos <strong>de</strong> documento, lo que hace que no sea sencillo<br />
i<strong>de</strong>ntificar que operaciones están permitidas en cada uno <strong>de</strong> ellos. Todo lo anterior hace que<br />
el uso <strong>de</strong>l módulo no sea intuitivo ni sencillo a la hora <strong>de</strong> trabajar con documentos <strong>de</strong> hojas<br />
<strong>de</strong> cálculo.<br />
OpenOffice-OODoc lleva en <strong>de</strong>sarrollo <strong>de</strong>s<strong>de</strong> el 2004, siendo la última versión liberada<br />
<strong>de</strong> julio <strong>de</strong> 2010, el soporte se ofrece a través <strong>de</strong> los foros <strong>de</strong> CPAN [CPA], por todo ello este<br />
módulo cuenta con una madurez alta, una actividad actual baja y un soporte medio.<br />
2.2.9. Java Excel API<br />
Java Excel API es un API para Java que permite leer, modificar y generar documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo con formato Excel en las versiones 95 y 97-2000 a través <strong>de</strong> la implementación<br />
<strong>de</strong> los estándares <strong>de</strong> dichos formatos.<br />
Ejemplo <strong>de</strong> código usando Java Exel API<br />
En este apartado se muestra un ejemplo don<strong>de</strong> se llevan a cabo las mismas operaciones<br />
que se han realizado en los ejemplos <strong>de</strong> otras alternativas. El ejemplo consiste en crear un<br />
nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo al que le aña<strong>de</strong> una nueva hoja <strong>de</strong> cálculo y le asigna<br />
valores a dos celdas. El objetivo <strong>de</strong> este apartado es el <strong>de</strong> ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong><br />
uso <strong>de</strong> la alternativa.<br />
WritableWorkbook workbook = Workbook.createWorkbook(new File("output.xls"<br />
));<br />
WritableSheet sheet = workbook.createSheet("Hoja_prueba", 0);<br />
jxl.write.Number number = new jxl.write.Number(0, 0, 16.6); //Celda A1<br />
sheet.addCell(number);<br />
number = new jxl.write.Number(1, 1, 199);//Celda B2<br />
sheet.addCell(number);<br />
workbook.write();<br />
workbook.close();<br />
Listado 2.20: Ejemplo uso Java Excel API<br />
En el listado 2.20 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar las operaciones sobre un<br />
nuevo documento <strong>de</strong> hojas cálculo. Los pasos seguidos han sido los siguientes:
26 2. ANTECEDENTES<br />
1. Se ha creado un nuevo documento xls creando un nuevo objeto WritableWorkbook<br />
2. Se ha añadido al documento una nueva hoja <strong>de</strong> cálculo, usando el método correspondiente<br />
para ello createWorkbook. Este método nos <strong>de</strong>vuelve el objeto WritableSheet<br />
que representa la hoja creada.<br />
3. Para po<strong>de</strong>r asignar un valor a una celda, antes es necesario crear un objeto con el<br />
formato <strong>de</strong>l dato a insertar, es <strong>de</strong>cir, un objeto que representa el contenido <strong>de</strong> la celda<br />
y su posición; en el ejemplo al insertar un valor numérico se hace uso <strong>de</strong>l objeto<br />
jxl.write.Number. Si se <strong>de</strong>seará insertar una ca<strong>de</strong>na entonces sería necesario crear un<br />
objeto jxl.write.<strong>La</strong>bel.<br />
4. Una vez creado el objeto que representa al contenido <strong>de</strong> la celda, se inserta a la hoja<br />
<strong>de</strong> cálculo <strong>de</strong>seada a través <strong>de</strong> su método addCell.<br />
5. El último paso consiste en escribir los cambios que se han realizado en el documento<br />
y cerrarlo para liberar los recursos asociados al mismo.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa trabaja con el formato xls en las versiones 95 y 97-2000 Excel, permitiendo<br />
realizar la mayoría <strong>de</strong> las operaciones con las limitaciones <strong>de</strong> que no da la posibilidad<br />
<strong>de</strong> generar macros ni gráficos, no obstante si el fichero a modificar contiene alguno <strong>de</strong> estos<br />
elementos los preservará.<br />
El lenguaje <strong>de</strong> programación usado es Java, y al estar la librería escrita completamente en<br />
dicho lenguaje hace que esta alternativa sea multiplataforma, pudiendo usarse en cualquier<br />
sistema que tenga una implementación <strong>de</strong> máquina virtual <strong>de</strong> Java.<br />
<strong>La</strong> librería tiene una licencia LGPL por tanto la aplicación que implemente esta alternativa<br />
pue<strong>de</strong> ser libre o con licencia privativa.<br />
<strong>La</strong> dificultad es sencilla pues los objetos y métodos para trabajar con ellos son intuitivos<br />
y están bien organizados, permitiendo coger rápidamente la filosofía seguida por esta API.<br />
A<strong>de</strong>más se proporciona una documentación muy completa con un tutorial que facilita todavía<br />
más su uso.<br />
Java Excel API empezó en 2002 a partir <strong>de</strong> la implementación basada en ExcelRead,<br />
siendo la última versión liberada <strong>de</strong> octubre <strong>de</strong> 2009. Para el soporte cuenta con un grupo<br />
creado en Yahoo. A partir <strong>de</strong> la información anterior se pue<strong>de</strong> <strong>de</strong>cir que la librería tiene una<br />
madurez alta, con una actividad actual nula y un soporte medio.
2. ANTECEDENTES 27<br />
2.2.10. GemBox.SpreadSheet<br />
GemBox.SpreadSheet [Sof] es un componente .NET que permite a los <strong>de</strong>sarrolladores<br />
escribir, leer y convertir ficheros <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo a través <strong>de</strong> una API sin<br />
necesidad <strong>de</strong> tener instaladas otras aplicaciones. GemBox.SpreadSheet es compatible con<br />
los formatos <strong>de</strong> Excel 97-2007 (xls y xlsx) y Open Document a través <strong>de</strong> la implementación<br />
<strong>de</strong> los estándares <strong>de</strong> dichos formatos. Tiene las siguientes limitaciones:<br />
<strong>La</strong>s imágenes y comentarios sólo se soportan en los formatos xlsx y ods.<br />
Sólo se conserva la información <strong>de</strong> gráficos y <strong>de</strong> tablas dinámicas , en inglés pivot<br />
tables, para el formato xlsx.<br />
Ejemplo <strong>de</strong> código usando GemBox.SpreadSheet<br />
En este apartado se muestra cómo realizar el ejemplo ilustrado en otras alternativas esta<br />
vez haciendo uso <strong>de</strong> la librería GemBox.SpreadSheet. El ejemplo consiste en crear un nuevo<br />
documento <strong>de</strong> hojas <strong>de</strong> cálculo, añadirle una nueva hoja <strong>de</strong> cálculo, asignarle valores a<br />
dos celdas y salvar el documento. El objetivo <strong>de</strong> este ejemplo es el <strong>de</strong> ilustrar el nivel <strong>de</strong><br />
complejidad <strong>de</strong> uso <strong>de</strong> la alternativa.<br />
ExcelFile excelFile = new ExcelFile();<br />
ExcelWorksheetCollection worksheets = excelFile.Worksheets;<br />
ExcelWorksheet ws = worksheets.Add("Hoja_prueba")<br />
ws.Cells["A1"].Value = 16;<br />
ws.Cells["B2"].Value = 199;<br />
excelFile.SaveXls("ejemplo.xls");<br />
Listado 2.21: Ejemplo uso GemBox.SpreadSheet<br />
En el listado 2.21 se pue<strong>de</strong> ver el código resultante <strong>de</strong>l ejemplo, en el que primero se<br />
realizar la creación <strong>de</strong>l documento <strong>de</strong> hojas <strong>de</strong> cálculo, en este caso con formato Excel, para<br />
<strong>de</strong>spués recuperar la colección <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong>l documento a la que se le aña<strong>de</strong> una<br />
nueva hoja <strong>de</strong> cálculo, que será a la que se le asignen los valores numéricos a dos <strong>de</strong> sus<br />
celdas.<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con las diferentes versiones <strong>de</strong>l formato Microsot Excel<br />
y Open Document, pero la modificación <strong>de</strong> ficheros xls que hayan sido creados con otras<br />
herramientas pue<strong>de</strong> provocar pérdida <strong>de</strong> alguna información como gráficos y tablas dinámicas.
28 2. ANTECEDENTES<br />
El lenguaje <strong>de</strong> programación a usar pue<strong>de</strong> ser cualquiera <strong>de</strong> la plataforma .NET. Esta<br />
alternativa sólo se pue<strong>de</strong> usar en sistemas Windows.<br />
GemBox.SpreadSheet tiene licencia privativa, y una licencia gratuita que permite el uso<br />
<strong>de</strong> la API con limitaciones (un máximo <strong>de</strong> 150 filas por hoja <strong>de</strong> cálculo, y 5 hojas por documento).<br />
<strong>La</strong> dificultad es sencilla pues los métodos son bastantes explícitos, se proporciona un fichero<br />
<strong>de</strong> ayuda para usarlo con el entorno <strong>de</strong> <strong>de</strong>sarrollo Visual Studio, y a<strong>de</strong>más se proporcionan<br />
varios ejemplos que ilustran las diferentes operaciones que se pue<strong>de</strong>n realizar.<br />
<strong>La</strong> madurez y actividad <strong>de</strong> la solución son más difíciles <strong>de</strong> analizar en productos con licencia<br />
privativa que con alternativas <strong>de</strong> código abierto en las que se pue<strong>de</strong> acce<strong>de</strong>r al repositorio<br />
para ver ambas características por tanto no se evaluarán. En este caso lo que si es muy alto<br />
es el soporte pues se pue<strong>de</strong> contratar.<br />
2.2.11. Spreadsheet SDK<br />
Spreadsheet SDK [Byt] es un componente .NET que permite a los <strong>de</strong>sarrolladores escribir,<br />
leer y convertir ficheros <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo a través <strong>de</strong> una API sin necesidad<br />
<strong>de</strong> tener instaladas otras aplicaciones. Spreadsheet SDK es compatible con los formatos <strong>de</strong><br />
Excel 97-2010 (xls y xlsx) y Open Document a través <strong>de</strong> la implementación <strong>de</strong> los estándares<br />
<strong>de</strong> dichos formatos, y permite la exportación en diferentes formatos incluido PDF.<br />
Ejemplo <strong>de</strong> código usando Spreadsheet SDK<br />
En este apartado se muestra cómo realizar el ejemplo usado en otras alternativas haciendo<br />
uso <strong>de</strong> la API Spreadsheet SDK. El ejemplo consiste en crear un nuevo documento <strong>de</strong> hojas<br />
<strong>de</strong> cálculo, añadirle una nueva hoja <strong>de</strong> cálculo, asignarle valores a dos celdas y salvar el<br />
documento. El objetivo <strong>de</strong> este ejemplo es el <strong>de</strong> ilustrar el nivel <strong>de</strong> complejidad <strong>de</strong> uso <strong>de</strong> la<br />
alternativa.<br />
Spreadsheet document = new Spreadsheet();<br />
Worksheet worksheet = document.Workbook.Worksheets.Add("Hoja_prueba");<br />
worksheet.Cell(0, 0).Value = 16;<br />
worksheet.Cell(1, 1).Value = 199;<br />
document.SaveAs("ejemplo.xls");<br />
Listado 2.22: Ejemplo uso Spreadsheet SDK<br />
En el listado 2.22 se pue<strong>de</strong> ver el código resultante <strong>de</strong> realizar la creación <strong>de</strong>l documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo, en este caso con formato Excel, se recupera la colección <strong>de</strong> hojas <strong>de</strong><br />
cálculo <strong>de</strong>l documento para añadir una nueva, y se le asignan valores a dos <strong>de</strong> sus celdas.
2. ANTECEDENTES 29<br />
Características <strong>de</strong> la alternativa<br />
Una vez introducida la alternativa, se van a analizar las diferentes características comentadas<br />
en la introducción <strong>de</strong>l capítulo.<br />
Esta alternativa permite trabajar con las diferentes versiones <strong>de</strong>l formato Microsot Excel y<br />
Open Document, permitiendo la modificación <strong>de</strong> documentos ya creados con Microsoft Excel<br />
sin pérdida <strong>de</strong> información. A<strong>de</strong>más, permite la exportación a PDF y otros formatos.<br />
El lenguaje <strong>de</strong> programación permitido para trabajar con esta alternativa pue<strong>de</strong> ser cualquiera<br />
<strong>de</strong> la plataforma .NET. Este módulo sólo se pue<strong>de</strong> usar en sistemas Windows.<br />
Spreadsheet SDK tiene licencia privativa.<br />
<strong>La</strong> dificultad es sencilla pues los métodos son bastantes explícitos, y a<strong>de</strong>más se proporciona<br />
documentación y varios ejemplos que ilustran las diferentes operaciones que se pue<strong>de</strong>n<br />
realizar.<br />
<strong>La</strong> madurez y actividad <strong>de</strong> la solución son más difíciles <strong>de</strong> analizar en productos con licencia<br />
privativa que con alternativas <strong>de</strong> código abierto en las que se pue<strong>de</strong> acce<strong>de</strong>r al repositorio<br />
para ver ambas características por tanto no se evaluarán. En este caso lo que si es muy alto<br />
es el soporte pues se pue<strong>de</strong> contratar.<br />
2.2.12. Comparativa <strong>de</strong> alternativas<br />
En esta sección se preten<strong>de</strong> dar una visión general <strong>de</strong> las alternativas estudiadas en el<br />
capítulo a través <strong>de</strong> la comparación <strong>de</strong> la características analizadas. Para ello se han creado<br />
dos cuadros comparativos que se analizarán a continuación.<br />
Comparativa <strong>de</strong> funcionalida<strong>de</strong>s<br />
En el cuadro 2.1 se realiza una comparación <strong>de</strong> las funcionalida<strong>de</strong>s puramente técnicas,<br />
representadas por las siguientes columnas:<br />
Lenguaje: es el lenguaje <strong>de</strong> programación con el que permite trabajar la alternativa.<br />
Formatos: son los formatos <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo que se soportan.<br />
C: representa la operación <strong>de</strong> Creación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
M: representa la operación <strong>de</strong> Modificación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
E: representa la operación <strong>de</strong> Exportación <strong>de</strong> información <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo.<br />
Cv: representa la operación <strong>de</strong> Conversión <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo a los<br />
formatos soportados.
30 2. ANTECEDENTES<br />
PDF: representa la operación <strong>de</strong> exportación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo al<br />
formato PDF.<br />
Plataforma: es la plataforma o sistema operativo don<strong>de</strong> se pue<strong>de</strong> utilizar la alternativa.<br />
Una vez se han explicado qué representa cada una <strong>de</strong> las columnas <strong>de</strong>l cuadro 2.1, vamos<br />
a analizar la información que se pue<strong>de</strong> extraer <strong>de</strong> él. Existen cuatro alternativas que<br />
permiten trabajar con los formatos más extendidos Excel y Open Document, estas son: OpenOffice.org<br />
con UNO, Spreadsheet::Read, GemBox.SpreadSheet, y Spreadsheet SDK. De<br />
las alternativas anteriores sólo dos permiten realizar todas las operaciones y conversiones:<br />
OpenOffice.org con UNO y Spreadsheet SDK, <strong>de</strong> las anteriores sólo la primera es multiplataforma.<br />
Nombre Lenguaje Formatos C M E Cv PDF Plataforma<br />
MS Office y COM C++ y otros Excel X X X X Windows<br />
OpenOffice.org y UNO Java y otros Excel y OOO X X X X X Varias<br />
Apache POI Java Excel X X X X Varias<br />
Spreadsheet::ParseExcel Perl xls X Varias<br />
Spreadsheet::Read Perl Excel y OOO X Varias<br />
Spreadsheet::WriteExcel Perl Excel X Varias<br />
OpenOffice::OODoc Perl OOO X X X Varias<br />
Java Excel API Java xls X X X Varias<br />
GemBox.SpreadSheet .Net Excel y OOO X X X X Windows<br />
Spreadsheet SDK .Net Excel y OOO X X X X X Windows<br />
Cuadro 2.1: Comparativa <strong>de</strong> funcionalida<strong>de</strong>s <strong>de</strong> las distintas alternativas<br />
Comparativa <strong>de</strong> características generales<br />
En el cuadro 2.2 se realiza una comparación <strong>de</strong> las características a tener en cuenta a la hora<br />
<strong>de</strong> elegir una alternativa y que van más allá <strong>de</strong> las puramente técnicas. Estas características<br />
son representadas por las siguientes columnas:<br />
Licencia: es la licencia que tiene la alternativa y que <strong>de</strong>be ser compatible con la licencia<br />
<strong>de</strong>l producto que la vaya a usar.<br />
Doc: Es la documentación y ejemplos con los que cuenta la solución. Normalmente<br />
cuanto mejor es la documentación antes y mejor se pue<strong>de</strong> llevar a cabo la implementación<br />
<strong>de</strong> un producto.<br />
Soporte: Es el soporte a fallos o problemas encontrados al utilizar la solución. Durante<br />
el <strong>de</strong>sarrollo hay riesgo <strong>de</strong> que aparezcan problemas y es importante contar con algún<br />
tipo <strong>de</strong> soporte que pueda reducir los tiempos en solucionarlos.
2. ANTECEDENTES 31<br />
Actividad: representa la actividad que tiene un proyecto, es <strong>de</strong>cir, cada cuanto tiempo<br />
se libera una nueva versión. Esta característica es importante porque se resuelven antes<br />
los problemas encontrados.<br />
Madurez: representa el tiempo y uso que tiene una solución, <strong>de</strong> manera que cuanto<br />
más tiempo y más uso tenga más madura será. Normalmente cuanto más madura es<br />
una solución mayor estabilidad tiene.<br />
Dif: Dificultad, característica que indica lo fácil o difícil que es usar una <strong>de</strong>terminada<br />
solución; En ella influye entre otros factores la documentación <strong>de</strong>l proyecto.<br />
Una vez se han explicado qué representa cada una <strong>de</strong> las columnas <strong>de</strong>l cuadro 2.2, vamos<br />
a analizar la información que se pue<strong>de</strong> extraer <strong>de</strong> él. Existen tres alternativas que tiene una<br />
documentación completa, junto con una madurez, actividad y soporte muy altos, estas son:<br />
Microsoft Office y COM, OpenOffice.org con UNO, y Apache POI. De las alternativas anteriores<br />
sólo las dos últimas tienen licencia libre, puesto que si se usa Microsoft Office se<br />
requiere adquirir una licencia <strong>de</strong> esta suite ofimática. A<strong>de</strong>más, <strong>de</strong> las alternativas libres sólo<br />
Apache POI tiene una dificultad baja.<br />
Nombre Licencia Doc. Soporte Actividad Madurez Dif.<br />
MS Office y COM privativa Completa Muy Alto Muy Alta Muy Alta Alta<br />
OpenOffice.org y UNO LGPL Completa Muy Alto Muy Alta Muy Alta Alta<br />
Apache POI Apache Completa Muy Alto Muy Alta Muy Alta Baja<br />
Spreadsheet::ParseExcel GPL Poca Medio Alta Alta Alta<br />
Spreadsheet::Read GPL Completa No Alta Alta Baja<br />
Spreadsheet::WriteExcel GPL Completa Alto Media Alta Baja<br />
OpenOffice::OODoc LGPL Completa Medio Baja Alta Alta<br />
Java Excel API LGPL Completa Medio Muy Baja Alta Baja<br />
GemBox.SpreadSheet privativa Completa Muy Alto - - Baja<br />
Spreadsheet SDK privativa Completa Muy Alto - - Baja<br />
Cuadro 2.2: Comparativa <strong>de</strong> características generales <strong>de</strong> las alternativas
Capítulo 3<br />
Objetivos <strong>de</strong>l proyecto<br />
EN la comparativa <strong>de</strong> alternativas realizada en el capítulo anterior, se pue<strong>de</strong> ver que<br />
<strong>de</strong> todas las alternativas estudiadas sólo tres (OpenOffice.org y UNO, GemBox.SpreadSheet<br />
y Spreadsheet SDK) permiten la posibilidad <strong>de</strong> insertar y extraer información <strong>de</strong> documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo con los principales formatos <strong>de</strong>l mercado, que son los formatos <strong>de</strong><br />
Microsoft Excel y los <strong>de</strong> OpenOffice.org Calc. De esas tres alternativas sólo OpenOffice.org<br />
tiene una licencia no privativa.<br />
<strong>La</strong> alternativa <strong>de</strong> usar OpenOffice.org a través <strong>de</strong> UNO es la más completa siendo multiplataforma<br />
y ofreciendo a los <strong>de</strong>sarrolladores la posibilidad <strong>de</strong> incluir toda funcionalidad <strong>de</strong><br />
su suite ofimática en sus aplicaciones. Pero esa gran funcionalidad ofrecida hace que su uso<br />
tenga una dificultad elevada y por tanto sea compleja <strong>de</strong> incluir en otras aplicaciones.<br />
El proyecto OpenSheet a través <strong>de</strong>l objetivo general y <strong>de</strong> los objetivos específicos preten<strong>de</strong><br />
cubrir ese vacío <strong>de</strong>tectado en el estudio realizado <strong>de</strong> las alternativas. En este capítulo se<br />
<strong>de</strong>scriben tanto los objetivos generales como los específicos para <strong>de</strong>terminar así el alcance<br />
<strong>de</strong>l proyecto.<br />
3.1. Objetivo general<br />
El objetivo general que persigue el proyecto es proporcionar mecanismos para po<strong>de</strong>r realizar<br />
la extracción e inserción <strong>de</strong> datos en los documentos <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong> manera<br />
automática y sencilla, soportando los principales formatos existentes en el mercado.<br />
3.2. Objetivos específicos<br />
Los objetivos específicos que persigue el proyecto son los siguientes:<br />
1. Permitir trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo con los siguientes formatos:<br />
xls [Mic08b], xlt y xlsx [Mic10a] [Mic10b] <strong>de</strong> la aplicación Microsoft Excel; ods y<br />
ots <strong>de</strong> Open Document Format [OAS07] [OAS10] para hojas <strong>de</strong> cálculo.<br />
2. Permitir realizar las siguientes operaciones con documentos <strong>de</strong> hojas <strong>de</strong> cálculo: crear<br />
33
34 3. OBJETIVOS DEL PROYECTO<br />
un nuevo documento, abrir un documento ya existente, extraer datos <strong>de</strong> celdas, insertar<br />
datos en celdas, crear nuevas hojas <strong>de</strong> cálculo y eliminar hojas <strong>de</strong> cálculo.<br />
3. Permitir conversiones <strong>de</strong> hojas <strong>de</strong> cálculo entre los formatos soportados, siempre y<br />
cuando las funciones incorporadas en las hojas <strong>de</strong> cálculo a exportar existan tanto el<br />
formato origen como en el <strong>de</strong>stino y a<strong>de</strong>más sean compatibles.<br />
4. Permitir la exportación <strong>de</strong> hojas <strong>de</strong> cálculo al formato pdf.<br />
5. Ser multiplataforma, soportando al menos los sistemas operativos Windows y GNU/-<br />
Linux.<br />
6. Proporcionar una librería que exponga como funcionalida<strong>de</strong>s los objetivos <strong>de</strong>l proyecto,<br />
permitiendo así su incorporación en otras aplicaciones y proyectos.<br />
7. Proporcionar una herramienta o comando que utilice la librería mencionada anteriormente,<br />
preparado para ejecutarse <strong>de</strong>s<strong>de</strong> un terminal o consola <strong>de</strong>l sistema para po<strong>de</strong>r<br />
ser usado en un procesamiento por lotes.<br />
8. Proporcionar un servicio web que haga uso <strong>de</strong> la librería mencionada anteriormente,<br />
ofreciendo las funcionalida<strong>de</strong>s <strong>de</strong> los objetivos <strong>de</strong>l proyecto <strong>de</strong> forma remota.<br />
A continuación, se <strong>de</strong>tallará cada uno <strong>de</strong> los ocho objetivos anteriores.<br />
3.2.1. Objetivo 1: Formatos soportados<br />
El primer objetivo consiste en permitir trabajar con aquellos formatos <strong>de</strong> documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo <strong>de</strong> los programas más extendidos: Microsoft Excel y OpenOffice.org Calc.<br />
Concretamente los formatos permitidos serán: xlt, xls, xlsx, ods y odt. Con este objetivo se<br />
preten<strong>de</strong> que se pueda trabajar <strong>de</strong> manera homogénea y sencilla con cualquier documento <strong>de</strong><br />
hojas <strong>de</strong> cálculo in<strong>de</strong>pendientemente <strong>de</strong> su formato.<br />
3.2.2. Objetivo 2: Operaciones permitidas<br />
El segundo objetivo fija las operaciones que se preten<strong>de</strong>n ofrecer para trabajar con documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo que tengan alguno <strong>de</strong> los formatos soportados, estas operaciones<br />
son:<br />
1. Crear nuevos documentos: se permitirá crear nuevos documentos <strong>de</strong> hojas <strong>de</strong> cálculo<br />
para po<strong>de</strong>r trabajar con ellos, y luego po<strong>de</strong>r almacenar las modificaciones realizadas.<br />
2. Abrir documentos: se permitirá abrir documentos <strong>de</strong> hojas <strong>de</strong> cálculo creados anteriormente<br />
por OpenSheet o por otros programas siempre y cuando su formato este<br />
soportado.
3. OBJETIVOS DEL PROYECTO 35<br />
3. Extraer datos: se permitirá extraer datos numéricos y textos <strong>de</strong> las celdas que forman<br />
parte <strong>de</strong> las distintas hojas <strong>de</strong> cálculo <strong>de</strong>l documento.<br />
4. Insertar datos: se permitirá insertar datos en las distintas celdas <strong>de</strong> las hojas <strong>de</strong> cálculo<br />
<strong>de</strong>l documento, ya sean datos numéricos o textos.<br />
5. Crear hojas <strong>de</strong> cálculo: se permitirá crear nuevas hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un documento.<br />
6. Eliminar hojas <strong>de</strong> cálculo: se permitirá eliminar hojas <strong>de</strong> cálculo que forman parte <strong>de</strong><br />
un documento.<br />
Todas las operaciones <strong>de</strong>ben ofrecer una forma <strong>de</strong> uso sencilla.<br />
3.2.3. Objetivo 3: Conversiones entre formatos<br />
El tercer objetivo es permitir <strong>de</strong> manera automática y sencilla la conversión <strong>de</strong> documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo entre los diferentes formatos soportados, siempre que los elementos<br />
incluidos en el formato <strong>de</strong> origen sean compatibles con los elementos <strong>de</strong>l formato <strong>de</strong>stino.<br />
3.2.4. Objetivo 4: Exportación a pdf<br />
El cuarto objetivo consiste en dar la opción <strong>de</strong> exportar al formato PDF un documento <strong>de</strong><br />
hojas <strong>de</strong> cálculo que tenga alguno <strong>de</strong> los formatos permitidos.<br />
3.2.5. Objetivo 5: Multiplataforma<br />
El quinto objetivo es conseguir que el proyecto sea multiplataforma, <strong>de</strong> manera que se permita<br />
su uso en diferentes sistemas operativos, concretamente, se <strong>de</strong>be soportar los sistemas<br />
operativos GNU/Linux y Windows.<br />
3.2.6. Objetivo 6: Librería<br />
El sexto objetivo consiste en proporcionar una librería o API que cumpla con todos los<br />
objetivos anteriores, <strong>de</strong> manera que permita incorporar la funcionalidad proporcionada en<br />
otras aplicaciones.<br />
3.2.7. Objetivo 7: Comando<br />
El séptimo objetivo consiste en usar la librería <strong>de</strong>l objetivo anterior para implementar una<br />
herramienta o comando que permita realizar las operaciones <strong>de</strong> inserción y extracción <strong>de</strong> datos,<br />
la conversión entre formatos y la exportación a PDF. Este comando <strong>de</strong>be estar preparado<br />
para ejecutarse <strong>de</strong>s<strong>de</strong> un terminal <strong>de</strong>l sistema, lo que permitirá automatizarlo fácilmente para<br />
usarlo en trabajo por lotes.
36 3. OBJETIVOS DEL PROYECTO<br />
3.2.8. Objetivo 8: Servicio web<br />
El último objetivo consiste en usar la librería <strong>de</strong>l sexto objetivo para implementar un servicio<br />
web que permita, al igual que el comando, realizar las operaciones <strong>de</strong> inserción y<br />
extracción <strong>de</strong> datos, la conversión entre formatos y la exportación a PDF. Al tratarse <strong>de</strong> un<br />
servicio web permitirá trabajar con los documentos <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong> forma remota.
Capítulo 4<br />
Método y entorno <strong>de</strong> trabajo<br />
EN este capítulo se va a <strong>de</strong>scribir tanto el método como el entorno <strong>de</strong> trabajo <strong>de</strong>l proyecto.<br />
En el método <strong>de</strong> trabajo se preten<strong>de</strong> en primer lugar ofrecer una <strong>de</strong>scripción<br />
<strong>de</strong> las metodologías utilizadas para conocer en qué consisten, y luego explicar cómo se han<br />
adaptado para po<strong>de</strong>r usarlas en el marco <strong>de</strong> trabajo <strong>de</strong> un proyecto fin <strong>de</strong> carrera. En en el<br />
entorno <strong>de</strong> trabajo se enumerarán las diferentes herramientas y aplicaciones software usadas<br />
a lo largo <strong>de</strong>l <strong>de</strong>sarrollo, con una breve <strong>de</strong>scripción <strong>de</strong> para qué sirven y cómo se han usado<br />
en el proyecto.<br />
4.1. Método <strong>de</strong> trabajo<br />
En esta sección se <strong>de</strong>scribe el método <strong>de</strong> trabajo usado para el <strong>de</strong>sarrollo <strong>de</strong>l proyecto, y<br />
las metodologías en las que se basa dicho método. Concretamente el método <strong>de</strong> trabajo se<br />
basa en el uso <strong>de</strong> metodologías ágiles: Scrum que se ha usado para la planificación y gestión<br />
<strong>de</strong>l proyecto, y Test Driven Development (<strong>de</strong>sarrollo dirigido por test) que se ha utilizado<br />
como metodología <strong>de</strong> <strong>de</strong>sarrollo. A continuación, se <strong>de</strong>scribirá con mayor <strong>de</strong>talle en qué<br />
consisten estas metodologías ágiles utilizadas y cómo se han adaptado para su aplicación en<br />
el proyecto realizado.<br />
4.1.1. Metodologías Ágiles<br />
Si por algo se caracteriza el método <strong>de</strong> trabajo utilizado es por que se basa en el uso <strong>de</strong><br />
metodologías ágiles, por lo que antes <strong>de</strong> entrar a <strong>de</strong>finir las metodologías concretas que se<br />
han usado es importante conocer el concepto <strong>de</strong> metodología ágil.<br />
<strong>La</strong>s metodologías <strong>de</strong> <strong>de</strong>sarrollo ágiles son metodologías <strong>de</strong> <strong>de</strong>sarrollo software basadas en<br />
el <strong>de</strong>sarrollo iterativo, don<strong>de</strong> se consi<strong>de</strong>ra que los requisitos y las soluciones van evolucionando<br />
a lo largo <strong>de</strong> todo el <strong>de</strong>sarrollo, y por tanto se da más importancia a la capacidad <strong>de</strong><br />
adaptarse rápidamente a esos cambios que a la capacidad para aplicar medidas <strong>de</strong> contingencia<br />
que eviten que los cambios <strong>de</strong>tectados afecten a la planificación establecida.<br />
37
38 4. MÉTODO Y ENTORNO DE TRABAJO<br />
Manifiesto Ágil<br />
El término <strong>de</strong> <strong>de</strong>sarrollo ágil <strong>de</strong> software fue acuñado en el 2001 cuando un grupo <strong>de</strong><br />
<strong>de</strong>sarrolladores convocados por Kent Beck se reunió para discutir sobre los métodos <strong>de</strong><br />
<strong>de</strong>sarrollo <strong>de</strong> software ligeros, <strong>de</strong> esa reunión surgió el manifiesto <strong>de</strong>l <strong>de</strong>sarrollo <strong>de</strong> software<br />
ágil [BBvB + 01]:<br />
Estamos <strong>de</strong>scubriendo formas mejores <strong>de</strong> <strong>de</strong>sarrollar<br />
software tanto por nuestra propia experiencia como<br />
ayudando a terceros. A través <strong>de</strong> este trabajo hemos<br />
aprendido a valorar:<br />
Individuos e interacciones sobre procesos y herramientas<br />
Software funcionando sobre documentación extensiva<br />
Colaboración con el cliente sobre negociación contractual<br />
Respuesta ante el cambio sobre seguir un plan<br />
Esto es, aunque valoramos los elementos <strong>de</strong> la <strong>de</strong>recha,<br />
valoramos más los <strong>de</strong> la izquierda.<br />
Los doce principios que sigue el manifiesto ágil [BBvB + 01] son:<br />
1. Nuestra mayor prioridad es satisfacer al cliente mediante la entrega temprana y continua<br />
<strong>de</strong> software con valor.<br />
2. Aceptamos que los requisitos cambien, incluso en etapas tardías <strong>de</strong>l <strong>de</strong>sarrollo. Los<br />
procesos Ágiles aprovechan el cambio para proporcionar ventaja competitiva al cliente.<br />
3. Entregamos software funcional frecuentemente, entre dos semanas y dos meses, con<br />
preferencia al periodo <strong>de</strong> tiempo más corto posible.<br />
4. Los responsables <strong>de</strong> negocio y los <strong>de</strong>sarrolladores trabajamos juntos <strong>de</strong> forma cotidiana<br />
durante todo el proyecto.<br />
5. Los proyectos se <strong>de</strong>sarrollan en torno a individuos motivados. Hay que darles el entorno<br />
y el apoyo que necesitan, y confiarles la ejecución <strong>de</strong>l trabajo.<br />
6. El método más eficiente y efectivo <strong>de</strong> comunicar información al equipo <strong>de</strong> <strong>de</strong>sarrollo<br />
y entre sus miembros es la conversación cara a cara.<br />
7. El software funcionando es la medida principal <strong>de</strong> progreso.
4. MÉTODO Y ENTORNO DE TRABAJO 39<br />
8. Los procesos Ágiles promueven el <strong>de</strong>sarrollo sostenible. Los promotores, <strong>de</strong>sarrolladores<br />
y usuarios <strong>de</strong>bemos ser capaces <strong>de</strong> mantener un ritmo constante <strong>de</strong> forma in<strong>de</strong>finida.<br />
9. <strong>La</strong> atención continua a la excelencia técnica y al buen diseño mejora la Agilidad.<br />
10. <strong>La</strong> simplicidad, o el arte <strong>de</strong> maximizar la cantidad <strong>de</strong> trabajo no realizado, es esencial.<br />
11. <strong>La</strong>s mejores arquitecturas, requisitos y diseños emergen <strong>de</strong> equipos auto-organizados.<br />
12. A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación<br />
ajustar y perfeccionar su comportamiento en consecuencia.<br />
Con estos doce principios queda patente qué es un <strong>de</strong>sarrollo ágil y qué persigue. Ahora<br />
se van a analizar las ventajas que se obtienen con estos principios.<br />
El primer principio <strong>de</strong> entregar al cliente software que funciona a lo largo <strong>de</strong> todo el <strong>de</strong>sarrollo<br />
tiene varias ventajas. <strong>La</strong> primera <strong>de</strong> ellas es que con cada entrega se pue<strong>de</strong> obtener<br />
realimentación continuamente <strong>de</strong>l cliente, <strong>de</strong> manera que este se implique directamente en<br />
el proyecto al usar dichos artefactos generados, y transmitiendo si lo que se va entregando<br />
correspon<strong>de</strong> a lo esperado o si se <strong>de</strong>tectan nuevas necesida<strong>de</strong>s. Esto hace que sin asistir a<br />
reuniones periódicas <strong>de</strong>l proyecto, cosa que la mayoría <strong>de</strong> veces para el cliente no es posible,<br />
el cliente esté implicado durante todo el <strong>de</strong>sarrollo. Otra ventaja es que el cliente pue<strong>de</strong> empezar<br />
a cubrir las necesida<strong>de</strong>s <strong>de</strong>l producto sin tener que esperar a que el proyecto finalice,<br />
que muchas veces son periodos <strong>de</strong> tiempos excesivamente largos que provocan que se acabe<br />
rechazando el producto en beneficio <strong>de</strong> otros productos ya terminados existentes en el mercado.<br />
Por último, la ventaja <strong>de</strong>s<strong>de</strong> el punto <strong>de</strong> vista económico es que se pue<strong>de</strong> ir facturando<br />
con cada entrega.<br />
El segundo principio que dice que hay que asumir y reaccionar frente a los cambios en los<br />
requisitos en cualquier etapa, es uno <strong>de</strong> los más importantes puesto que permite adaptarse<br />
rápidamente a nuevas necesida<strong>de</strong>s que surjan en el mercado, ofreciendo a la empresa una<br />
gran ventaja competitiva frente a aquellas que tienen mo<strong>de</strong>los <strong>de</strong> <strong>de</strong>sarrollo más pesados y<br />
que no podrán llegar a ciertas oportunida<strong>de</strong>s <strong>de</strong>l mercado. Este principio unido al primero,<br />
que habla <strong>de</strong> ir entregando software con funcionalidad, permite una reacción muy rápida a los<br />
cambios, y por tanto adaptarse al funcionamiento actual <strong>de</strong>l mercado don<strong>de</strong> las tecnologías<br />
y necesida<strong>de</strong>s cambian muy rápidamente.<br />
En los diferentes principios se pue<strong>de</strong> observar que las metodologías ágiles dan mucha importancia<br />
a las personas que forman el equipo <strong>de</strong> <strong>de</strong>sarrollo y a su comunicación, y a<strong>de</strong>más<br />
que implican a los responsables <strong>de</strong>l negocio. Todo lo anterior unido a la posibilidad <strong>de</strong> ir<br />
entregando software a lo largo <strong>de</strong>l proyecto hace posible que dichas entregas reflejen completamente<br />
las necesida<strong>de</strong>s comerciales <strong>de</strong> la empresa. Por ejemplo, si se tiene la necesidad
40 4. MÉTODO Y ENTORNO DE TRABAJO<br />
<strong>de</strong> disponer <strong>de</strong> <strong>de</strong>mostraciones técnicas para que el <strong>de</strong>partamento comercial pueda usarlas<br />
mientras el proyecto <strong>de</strong> <strong>de</strong>sarrollo avanza, y así po<strong>de</strong>r buscar clientes, se pue<strong>de</strong>n enfocar<br />
las entregas para cumplir con ese objetivo. Como las entregas que se van a usar en las <strong>de</strong>mostraciones<br />
siguen siendo el producto, con funcionalidad reducida, y no requieren que se<br />
<strong>de</strong>dique más tiempo a cumplir este objetivo, el tiempo y coste no varían, lo único necesario<br />
es priorizar los requisitos en función <strong>de</strong> las necesida<strong>de</strong>s.<br />
Por último, otra ventaja muy importante que se pue<strong>de</strong> obtener <strong>de</strong> algunos <strong>de</strong> los objetivos,<br />
es que se persigue el mejorar constantemente el proceso <strong>de</strong> <strong>de</strong>sarrollo a través <strong>de</strong> tratar <strong>de</strong><br />
maximizar la reutilización, <strong>de</strong> perseguir el buen diseño y la excelencia técnica, y sobre todo<br />
con las reflexiones colectivas periódicas que permiten analizar que se ha hecho mal para<br />
corregirlo y que se ha hecho bien para potenciarlo.<br />
4.1.2. Scrum<br />
En esta sección no se preten<strong>de</strong> dar una explicación extensa y profunda <strong>de</strong> Scrum, para eso<br />
se cuentan con libros y referencias en la web, si no que el objetivo perseguido es dar una<br />
visión global <strong>de</strong> Scrum y sus principales conceptos para enten<strong>de</strong>r en otros capítulos cómo se<br />
ha adaptado su uso en el proyecto, y compren<strong>de</strong>r mejor el capítulo <strong>de</strong> resultados.<br />
¿Por qué usar Scrum<br />
El escenario <strong>de</strong> negocio ha cambiado <strong>de</strong> manera que las necesida<strong>de</strong>s tecnológicas cambian<br />
rápidamente y aparecen otras nuevas, por lo que es necesario que los proyectos cuenten con<br />
una gran velocidad a la hora <strong>de</strong> reaccionar a esos cambios para dar una respuesta rápida que<br />
se traduzca en los productos reclamados por el mercado.<br />
Algunos autores [Pal07] comentan que pue<strong>de</strong> que estemos en una etapa en la que ha <strong>de</strong>jado<br />
<strong>de</strong> existir el concepto <strong>de</strong> producto final, y en su lugar existen productos en continua evolución<br />
a partir <strong>de</strong> los incrementos <strong>de</strong> funcionalidad <strong>de</strong> las versiones iniciales o versiones beta <strong>de</strong> un<br />
producto. De esta manera, el producto va cambiando e incorporando los nuevos requisitos<br />
para ofrecer cada poco tiempo nuevas versiones.<br />
Para permitir llevar a cabo proyectos cuyos productos se adapten <strong>de</strong> manera rápida a las<br />
necesida<strong>de</strong>s <strong>de</strong>l mercado, existe una metodología ágil para la gestión <strong>de</strong> proyectos llamada<br />
Scrum.<br />
¿Qué es Scrum<br />
Scrum es una metodología ágil que <strong>de</strong>fine un marco <strong>de</strong> trabajo iterativo e incremental<br />
para la gestión <strong>de</strong> proyectos. Esta metodología gestiona proyectos basándose en un mo<strong>de</strong>lo<br />
ágil, cuyo objetivo es permitir adaptarse rápidamente a cambios en los requisitos en lugar <strong>de</strong><br />
intentar i<strong>de</strong>ntificar todos los requisitos necesarios al comienzo <strong>de</strong>l proyecto.
4. MÉTODO Y ENTORNO DE TRABAJO 41<br />
Scrum ofrece un conjunto <strong>de</strong> prácticas y roles que pue<strong>de</strong>n usarse como mo<strong>de</strong>lo <strong>de</strong> referencia<br />
para <strong>de</strong>finir el proceso <strong>de</strong> <strong>de</strong>sarrollo concreto que se ejecutará en los proyectos. A<br />
continuación se <strong>de</strong>finen estos roles y conceptos.<br />
Roles<br />
En Scrum se pue<strong>de</strong>n i<strong>de</strong>ntificar los siguientes roles implicados directamente en el proceso:<br />
Dueño <strong>de</strong> poducto (product owner): es el responsable <strong>de</strong> representar y asegurarse que<br />
se cumple con la perspectiva <strong>de</strong> negocio y los intereses <strong>de</strong>l cliente. <strong>La</strong>s tareas que<br />
realiza son:<br />
• Añadir nuevos requisitos o historias <strong>de</strong> usuario en la pila <strong>de</strong> producto (product<br />
backlog).<br />
• Priorizar las historias <strong>de</strong> usuario.<br />
• Comprobar al finalizar un período <strong>de</strong> <strong>de</strong>sarrollo (sprint) que el producto resultante<br />
cumple con los objetivos comprometidos.<br />
Scrum master: es el responsable <strong>de</strong> que el equipo cumpla sus objetivos al finalizar el<br />
sprint y <strong>de</strong> que se cumplan las reglas <strong>de</strong> Scrum. <strong>La</strong>s tareas que realiza son:<br />
• Convoca y dirige las reuniones para realizar las estimaciones <strong>de</strong> historias y división<br />
en tareas. Tanto las estimaciones como la división en tareas las realiza<br />
conjuntamente todo el equipo.<br />
• Dirige las reuniones diarias <strong>de</strong> seguimiento llamadas scrum.<br />
• Asigna a los miembros <strong>de</strong>l equipo aquellas tareas que no han sido seleccionadas<br />
<strong>de</strong> manera voluntaria.<br />
Miembro <strong>de</strong> equipo (Scrum member): es el encargado <strong>de</strong> cumplir con las tareas elegidas<br />
o asignadas para que el equipo logre alcanzar el objetivo marcado en el sprint.<br />
En Scrum los equipos son multidisciplinares por lo que un miembro <strong>de</strong> equipo pue<strong>de</strong><br />
ser un <strong>de</strong>sarrollador, diseñador, etc.<br />
En la figura 4.1 se pue<strong>de</strong>n ver los tres roles principales con el elemento <strong>de</strong>l que es responsable<br />
cada uno: el dueño <strong>de</strong> producto es el responsable <strong>de</strong> la gestión <strong>de</strong> la pila <strong>de</strong> producto,<br />
el Scrum master es el responsable <strong>de</strong> la gestión <strong>de</strong> los sprints, y el miembro <strong>de</strong>l equipo es<br />
responsable <strong>de</strong> implementar las historias y tareas asignadas.<br />
A parte <strong>de</strong> los roles anteriores, directamente implicados en el proceso <strong>de</strong> Scrum, existen<br />
otros roles muy importantes que participan a través <strong>de</strong> la realimentación o feedback a partir<br />
<strong>de</strong>l análisis o uso <strong>de</strong> los productos generados en los sprints. Algunos <strong>de</strong> estos roles son:<br />
clientes, usuarios, gerentes, comerciales, etc.
42 4. MÉTODO Y ENTORNO DE TRABAJO<br />
Figura 4.1: Roles <strong>de</strong> Scrum<br />
Pila <strong>de</strong> Producto<br />
<strong>La</strong> pila <strong>de</strong> producto (product backlog) es una lista priorizada <strong>de</strong> todos los requisitos o<br />
historias <strong>de</strong> usuario que se <strong>de</strong>sean implementar en el producto. Estas historias <strong>de</strong> usuario,<br />
que es como se llaman a los requisitos en Scrum, son <strong>de</strong>finidas usando la terminología <strong>de</strong>l<br />
dueño <strong>de</strong> producto <strong>de</strong> modo que pueda trabajar con ellas sin problemas.<br />
<strong>La</strong> pila <strong>de</strong> producto es algo muy dinámico, don<strong>de</strong> se aña<strong>de</strong>n historias conforme se <strong>de</strong>tectan<br />
nuevas necesida<strong>de</strong>s, y don<strong>de</strong> la priorización va cambiando para que al principio <strong>de</strong><br />
la pila estén siempre las historias que se quieren implementar primero. El mantenimiento y<br />
priorización <strong>de</strong> la pila es llevado a cabo por el dueño <strong>de</strong> producto.<br />
Sprint<br />
Un sprint es el periodo <strong>de</strong> tiempo o iteración con un objetivo concreto, durante el cuál se<br />
implementan aquellas historias planificadas dando como resultado un incremento funcional<br />
<strong>de</strong>l producto. Normalmente la duración <strong>de</strong> los sprints no suele exce<strong>de</strong>r los dos meses <strong>de</strong><br />
<strong>de</strong>sarrollo para cumplir con los principios <strong>de</strong>l manifiesto ágil.<br />
Un proyecto implementa las historias <strong>de</strong> la pila <strong>de</strong> producto a través <strong>de</strong> su planificación<br />
en sprints. El número <strong>de</strong> historias que se pue<strong>de</strong>n planificar para que se implementen en cada<br />
sprint <strong>de</strong>pen<strong>de</strong> por un lado <strong>de</strong> la estimación en tiempo <strong>de</strong> cada historia y por otro <strong>de</strong> la<br />
velocidad <strong>de</strong>l equipo.<br />
En la figura 4.2 se pue<strong>de</strong> ver ilustrado la representación <strong>de</strong> un sprint, don<strong>de</strong> primero se<br />
seleccionan en or<strong>de</strong>n las historias que están en la pila <strong>de</strong> producto y se asignan al sprint<br />
que se va a comenzar, <strong>de</strong>spués se inicia el sprint y una vez ha transcurrido el tiempo fijado<br />
para su <strong>de</strong>sarrollo se obtiene como resultado el producto con las nuevas funcionalida<strong>de</strong>s<br />
implementadas.<br />
Antes <strong>de</strong>l comienzo <strong>de</strong> un sprint se realiza una reunión <strong>de</strong>l equipo con el dueño <strong>de</strong> producto<br />
para <strong>de</strong>cidir que historias se van a llevar a cabo en ese sprint, para ello las historias <strong>de</strong>ben
4. MÉTODO Y ENTORNO DE TRABAJO 43<br />
Figura 4.2: Representación <strong>de</strong> un sprint <strong>de</strong> Scrum<br />
estar estimadas, pues se irán añadiendo al sprint en el or<strong>de</strong>n establecido en la pila, hasta<br />
alcanzar la cantidad máxima <strong>de</strong> trabajo que pue<strong>de</strong> realizar el equipo, medida dada por la<br />
velocidad <strong>de</strong> equipo.<br />
Durante el <strong>de</strong>sarrollo <strong>de</strong>l sprint se utiliza un diagrama llamado burn-down, ver figura 4.3<br />
en el que se representa el estado <strong>de</strong> la implementación <strong>de</strong> las historias. Con este gráfico se<br />
pue<strong>de</strong> comprobar <strong>de</strong> manera visual si el sprint sigue con la planificación establecida, o se<br />
está produciendo alguna <strong>de</strong>sviación positiva o negativa, <strong>de</strong> manera que se pueda corregir<br />
rápidamente.<br />
Al final <strong>de</strong>l sprint se analiza el resultado <strong>de</strong>l mismo y se hace un análisis <strong>de</strong> todo los<br />
sucedido como por ejemplo si se ha cumplido completamente con la planificación,los factores<br />
que han puesto en peligro el funcionamiento <strong>de</strong>l mismo, qué cosas mejorar o cambiar,<br />
etc.<br />
Scrum<br />
Scrum es una reunión diaria, <strong>de</strong> no más <strong>de</strong> quince minutos, que realiza todo el equipo y<br />
don<strong>de</strong> se analiza el estado <strong>de</strong> las tareas. Esta reunión, que da nombre a la metodología, es<br />
una potente herramienta <strong>de</strong> comunicación para todo el equipo, puesto que permite conocer<br />
que está haciendo cada miembro, <strong>de</strong>tectar los problemas encontrados y a<strong>de</strong>más analizar la<br />
situación global <strong>de</strong>l sprint.<br />
4.1.3. Adaptación <strong>de</strong> Scrum al marco <strong>de</strong> trabajo<br />
En esta sección se va a explicar como se ha adaptado la metodología Scrum para po<strong>de</strong>r<br />
usarse en la gestión <strong>de</strong> un proyecto fin <strong>de</strong> carrera.<br />
Para la <strong>de</strong>finición <strong>de</strong>l proceso <strong>de</strong> Scrum se ha partido <strong>de</strong> las recomendaciones y experiencias<br />
transmitidas por Henrik Kniberg en su libro [Kni07], y una adaptación posterior <strong>de</strong>bido
44 4. MÉTODO Y ENTORNO DE TRABAJO<br />
Figura 4.3: Ejemplo <strong>de</strong> gráfico <strong>de</strong> burndown <strong>de</strong> un sprint<br />
a las características propias <strong>de</strong>l entorno don<strong>de</strong> se <strong>de</strong>bían aplicar. <strong>La</strong>s características a tener<br />
en cuenta en el proyecto son:<br />
Normalmente al aplicar Scrum se habla <strong>de</strong> un equipo <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong> varias personas<br />
y en este caso sólo existen dos personas para abordar el proyecto: el alumno que <strong>de</strong>be<br />
realizar el proyecto fin <strong>de</strong> carrera, y el director que tiene la labor <strong>de</strong> orientar durante el<br />
<strong>de</strong>sarrollo <strong>de</strong>l mismo.<br />
En este caso concreto, el alumno no se pue<strong>de</strong> <strong>de</strong>dicar a jornada completa al <strong>de</strong>sarrollo<br />
<strong>de</strong>l proyecto. El motivo es que el alumno trabaja a tiempo completo en otros proyectos,<br />
lo que hace que el número <strong>de</strong> horas diarias a <strong>de</strong>dicar sean muy limitadas, aumentando<br />
la dificultad <strong>de</strong> la gestión y planificación <strong>de</strong>l proyecto.<br />
Roles asignados<br />
Cuando se habla <strong>de</strong> Scrum se habla <strong>de</strong> equipos <strong>de</strong> <strong>de</strong>sarrollo y en el caso <strong>de</strong> un proyecto<br />
fin <strong>de</strong> carrera sólo hay un miembro <strong>de</strong> equipo, el alumno que lo va a realizar, y por otro<br />
lado está el director <strong>de</strong> proyecto cuyo objetivo es orientar durante el <strong>de</strong>sarrollo <strong>de</strong>l proyecto.<br />
Siguiendo el funcionamiento <strong>de</strong> Scrum es necesario que los principales roles <strong>de</strong>l proceso<br />
sean asignados, pero en este caso teniendo en cuenta el número tan reducido <strong>de</strong> personas con<br />
las que se cuenta para que la asignación <strong>de</strong> los roles encajen lo mejor posible. Los roles se<br />
van a asignar <strong>de</strong> la siguiente forma:<br />
El dueño <strong>de</strong>l producto será el director <strong>de</strong>l proyecto pues tiene la capacidad <strong>de</strong> i<strong>de</strong>nti-
4. MÉTODO Y ENTORNO DE TRABAJO 45<br />
ficar las priorida<strong>de</strong>s que <strong>de</strong>ben cumplirse para lograr tener un producto con la calidad<br />
suficiente para que sea aceptado por el cliente. En este caso el cliente es el tribunal<br />
que <strong>de</strong>be evaluar el proyecto, y el producto es el proyecto fin <strong>de</strong> carrera que siga la<br />
normativa académica establecida.<br />
El rol Scrum master será llevado a cabo por el alumno pues uno <strong>de</strong> los objetivos <strong>de</strong>l<br />
proyecto fin <strong>de</strong> carrera <strong>de</strong>be ser <strong>de</strong>mostrar las aptitu<strong>de</strong>s para la planificación y gestión<br />
<strong>de</strong> proyectos.<br />
El último rol por asignar es el <strong>de</strong> miembro <strong>de</strong> equipo que <strong>de</strong>be ser llevado a cabo por<br />
el alumno, don<strong>de</strong> tendrá el papel <strong>de</strong> <strong>de</strong>sarrollador.<br />
Por tanto el director <strong>de</strong> proyecto asumirá la responsabilidad <strong>de</strong> establecer la prioridad <strong>de</strong><br />
las tareas siempre en comunicación con el Scrum master y será quién evalúe las entregas o<br />
<strong>de</strong>mostraciones realizadas al finalizar cada sprint.<br />
El alumno a parte <strong>de</strong> llevar el trabajo <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong>berá gestionar el proyecto, realizando<br />
la estimación <strong>de</strong> las historias. A<strong>de</strong>más la planificación <strong>de</strong> los sprints se <strong>de</strong>berán realizar con<br />
la aprobación <strong>de</strong>l dueño <strong>de</strong> producto.<br />
I<strong>de</strong>ntificación <strong>de</strong> historias: pila <strong>de</strong> producto<br />
<strong>La</strong> pila <strong>de</strong> producto, siguiendo en parte las indicaciones <strong>de</strong>l libro anteriormente mencionado<br />
[Kni07], se realizará <strong>de</strong> manera que a cada historia se le van a asignar los siguientes<br />
campos:<br />
ID: Es el i<strong>de</strong>ntificador único <strong>de</strong> la historia que permite hacer el seguimiento durante<br />
todo el <strong>de</strong>sarrollo permitiendo así que cambie <strong>de</strong> nombre en algún momento si se<br />
consi<strong>de</strong>ra a<strong>de</strong>cuado. El i<strong>de</strong>ntificador usado será un numero entero para las historias,<br />
y para las subhistorias un número <strong>de</strong>cimal don<strong>de</strong> la parte entera será el i<strong>de</strong>ntificador<br />
<strong>de</strong> la historia padre. Así si una hay dos subhistorias que parten <strong>de</strong> la historia con id 3,<br />
entonces esas subhistorias tendrán como ids 3.1 y 3.2 respectivamente.<br />
Nombre: Es nombre <strong>de</strong>scriptivo <strong>de</strong> la funcionalidad que representa, <strong>de</strong>be ser entendida<br />
por el dueño <strong>de</strong> producto.<br />
Descripción: Es una pequeña <strong>de</strong>scripción con <strong>de</strong>talles concretos don<strong>de</strong> se explica en<br />
qué consiste la historia.<br />
Estimación: Es la estimación inicial <strong>de</strong>l tiempo que va a tardar en realizar la historia.<br />
<strong>La</strong> estimación se da en puntos historia que se explicarán más a<strong>de</strong>lante.<br />
Cómo probarlo: Es una <strong>de</strong>scripción <strong>de</strong> los test que se <strong>de</strong>ben realizar con éxito para<br />
enten<strong>de</strong>r que la historia ha sido completada. Esto como se verá más a<strong>de</strong>lante se podrá<br />
utilizar como punto <strong>de</strong> entrada en el <strong>de</strong>sarrollo dirigido por tests.
46 4. MÉTODO Y ENTORNO DE TRABAJO<br />
Notas: Son <strong>de</strong>talles a tener en cuenta a la hora planificar la historia en algún sprint.<br />
En estos <strong>de</strong>talles se pue<strong>de</strong>n incluir por ejemplo las <strong>de</strong>pen<strong>de</strong>ncias entre historias, <strong>de</strong><br />
manera que si el dueño <strong>de</strong> producto quiere alguna tarea que <strong>de</strong>penda <strong>de</strong> otra, ambas<br />
<strong>de</strong>ben ser planificadas en el sprint o esperar a que la <strong>de</strong>pen<strong>de</strong>ncia esté terminada.<br />
Importancia: Es valor numérico asignado por el dueño <strong>de</strong> producto y que prioriza la<br />
pila <strong>de</strong> producto. No existe un valor máximo, simplemente cuanto mayor sea el número<br />
más importante es la historia. Es recomendable no usar valores secuenciales a la hora<br />
<strong>de</strong> asignar las priorida<strong>de</strong>s para permitir, en caso <strong>de</strong> necesitarse, que las historias nuevas<br />
puedan situarse entre medias <strong>de</strong> historias ya existentes.<br />
Aunque en otros proyectos normalmente no se planifican todas las historias en sprints directamente,<br />
sino que se planifican aquellas que correspon<strong>de</strong>n a un sprint, es <strong>de</strong>cir, se hace<br />
una planificación <strong>de</strong> sprint en sprint; en este proyecto al tener una fecha límite para su finalización,<br />
es necesario realizar la planificación completa para conocer así el tiempo que<br />
se necesita para completarlo. Para ello se <strong>de</strong>be realizar la asignación <strong>de</strong> todas las tareas en<br />
sprints y comprobar así si con esa planificación inicial se dispone <strong>de</strong>l tiempo suficiente.<br />
División en Sprints<br />
En esta adaptación <strong>de</strong> Scrum se ha asignado a cada sprint una duración <strong>de</strong> una semana,<br />
<strong>de</strong> manera que al final <strong>de</strong> cada semana se haga una reunión <strong>de</strong> sprint o se envíe un correo al<br />
dueño <strong>de</strong>l producto don<strong>de</strong> se muestren las historias completadas. El objetivo es analizar la<br />
evolución <strong>de</strong>l proyecto y <strong>de</strong> los productos semanalmente; <strong>de</strong> esta manera se permite <strong>de</strong>tectar<br />
las posibles <strong>de</strong>sviaciones <strong>de</strong> tiempo muy rápidamente, puesto que en este caso concreto el<br />
alumno no pue<strong>de</strong> tener <strong>de</strong>dicación completa en el proyecto y eso provoca que toda <strong>de</strong>sviación<br />
pueda <strong>de</strong>sembocar en un retraso excesivo. Así en el caso <strong>de</strong> <strong>de</strong>tectar una <strong>de</strong>sviación una<br />
semana, se usará como medida correctora, siempre que sea posible, el aumento el número <strong>de</strong><br />
horas a <strong>de</strong>dicar en el siguiente sprint; una forma <strong>de</strong> aumentar el número <strong>de</strong> horas pue<strong>de</strong> ser<br />
mediante el uso <strong>de</strong> días <strong>de</strong> vacaciones <strong>de</strong>l trabajo principal.<br />
Para po<strong>de</strong>r realizar la división en sprints primero hay que establecer la velocidad <strong>de</strong> <strong>de</strong>sarrollo<br />
<strong>de</strong>l equipo <strong>de</strong> Scrum, y cómo se mi<strong>de</strong>n los puntos por historia. En este proyecto se<br />
ha <strong>de</strong>cidido que 4 puntos <strong>de</strong> historia correspon<strong>de</strong> a una semana <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong>dicando 27<br />
horas <strong>de</strong> trabajo que son las horas que el miembro <strong>de</strong>l equipo pue<strong>de</strong> <strong>de</strong>dicar sin hacer una<br />
sobre-estimación, por tanto, la velocidad <strong>de</strong> equipo se establecerá en 4 puntos.<br />
Herramienta para planificación<br />
Para po<strong>de</strong>r llevar la planificación se usará un documento <strong>de</strong> hojas <strong>de</strong> cálculo con tres hojas<br />
don<strong>de</strong> se guardará toda la información necesaria para realizar la planificación siguiendo la<br />
adaptación <strong>de</strong> Scrum:
4. MÉTODO Y ENTORNO DE TRABAJO 47<br />
Semanas: en esta hoja se muestra la información <strong>de</strong> todas las semanas disponibles<br />
hasta la fecha límite <strong>de</strong> entrega <strong>de</strong>l proyecto, y en cada una <strong>de</strong> ellas toda la información<br />
resumen <strong>de</strong> la planificación. Esta tabla tiene los siguientes elementos:<br />
• Semana: indica el número <strong>de</strong> semana.<br />
• Comienzo: indica que día <strong>de</strong>l mes comienza la semana <strong>de</strong> trabajo.<br />
• Fin: indica que día <strong>de</strong>l mes en el que finaliza esa semana <strong>de</strong> trabajo.<br />
• Objetivo: es el nombre <strong>de</strong>l objetivo que persigue el sprint planificado esa semana.<br />
• Historias: contiene los i<strong>de</strong>ntificadores <strong>de</strong> las historias planificadas para esa semana.<br />
• Velocidad estimada: es la velocidad que se ha estimado que tendrá el equipo.<br />
• Velocidad real: es la velocidad final que el equipo ha tenido en esa semana.<br />
• Completado Fecha: contiene la fecha real en la que se han terminado todas las<br />
historias <strong>de</strong>l sprint.<br />
Historias: en esta hoja se muestra la información en <strong>de</strong>talle <strong>de</strong> todas las historias y<br />
subhistorias con todos los elementos que contiene una historia excepto el campo que<br />
indica la importancia. Esta hoja sirve para po<strong>de</strong>r conocer los <strong>de</strong>talles concretos <strong>de</strong><br />
cada historia <strong>de</strong> manera que tiene como principales usuarios los roles <strong>de</strong> Scrum master<br />
y miembro <strong>de</strong> equipo, puesto que será la hoja que usen para estimar y para conocer<br />
que se <strong>de</strong>be implementar en cada historia.<br />
Product Backlog: es la hoja que representa la pila <strong>de</strong> producto, y por tanto la que <strong>de</strong>be<br />
usar el dueño <strong>de</strong> producto para priorizar las historias. Esta hoja contiene una tabla con<br />
los siguientes elementos:<br />
• ID: indica el i<strong>de</strong>ntificador <strong>de</strong> la historia.<br />
• Nombre: indica el nombre <strong>de</strong> la historia para que el dueño <strong>de</strong> producto pueda<br />
i<strong>de</strong>ntificarla mejor.<br />
• Importancia: es el valor numérico que le <strong>de</strong>be asignar el dueño <strong>de</strong> producto,<br />
cuanto mayor sea el valor más importancia tendrá. <strong>La</strong>s historias más importante<br />
están más arriba <strong>de</strong> la pila siendo las primeras en implementarse.<br />
• Estimación: son los puntos <strong>de</strong> historia estimados que indican la duración <strong>de</strong> esa<br />
historia. Hay que tenerlos en cuenta a la hora <strong>de</strong> po<strong>de</strong>r asignar historias a un<br />
sprint.<br />
• Sprint: I<strong>de</strong>ntificador <strong>de</strong>l sprint al que se ha asignado la historia.<br />
• Velocidad estimada: es la velocidad que se ha estimado que tendrá el equipo en<br />
ese sprint.
48 4. MÉTODO Y ENTORNO DE TRABAJO<br />
• Velocidad real: es la velocidad final que el equipo ha tenido en en ese sprint.<br />
• Estado: indica si la historia ha sido completada, es <strong>de</strong>cir, se ha probado que<br />
cumple con lo establecido en el campo <strong>de</strong> cómo probarlo.<br />
<strong>La</strong>s tres tablas anteriores en un documento <strong>de</strong> hojas <strong>de</strong> cálculo, junto con las opciones<br />
que proporciona OpenOffice.org Calc como son la <strong>de</strong> reor<strong>de</strong>nar por el valor <strong>de</strong> un campo,<br />
añadir nuevas historias, mover elementos, etc; es suficiente para llevar la información <strong>de</strong><br />
planificación y gestión <strong>de</strong>l proyecto.<br />
4.1.4. Desarrollo dirigido por tests<br />
El <strong>de</strong>sarrollo dirigido por test o TDD es una técnica ágil <strong>de</strong> diseño y <strong>de</strong>sarrollo <strong>de</strong> software<br />
que se caracteriza por comenzar primero con la creación <strong>de</strong> los test unitarios que prueban<br />
los requisitos <strong>de</strong>l proyecto, creando a continuación el código que cumple con esas pruebas,<br />
es <strong>de</strong>cir, que a partir <strong>de</strong> esas pruebas se realiza la implementación <strong>de</strong> los requisitos. De esta<br />
característica recibe su nombre, pues son los test unitarios los que dirigen el <strong>de</strong>sarrollo. <strong>La</strong><br />
técnica <strong>de</strong> TDD se basa en tres pilares fundamentales [Car10] :<br />
1. <strong>La</strong> implementación <strong>de</strong> sólo aquellas funciones que son necesarias, y ninguna más. Se<br />
trata <strong>de</strong> evitar el hecho <strong>de</strong> generar código para tratar <strong>de</strong> adaptarse a posibles cambios,<br />
cuando en realidad sólo se está tratando <strong>de</strong> prever futuros cambios, cosa en que las<br />
metodologías ágiles no es necesario, pues frente a la necesidad <strong>de</strong> predicción está la<br />
<strong>de</strong> adaptación.<br />
2. Minimizar el número <strong>de</strong> <strong>de</strong>fectos que se introducen en el software durante la fase <strong>de</strong><br />
producción.<br />
3. Hacer que el software sea modular, altamente reutilizable y preparado para el cambio.<br />
Para usar esta técnica hay que seguir un simple algoritmo <strong>de</strong> tres pasos.<br />
Algoritmo TDD<br />
El algoritmo para utilizar la técnica <strong>de</strong> TDD es el siguiente:<br />
1. Escribir la especificación <strong>de</strong>l requisito a través <strong>de</strong> un test.<br />
2. Implementar el código que cumple con dicho requisito, es <strong>de</strong>cir, que haga superar el<br />
test.<br />
3. Refactorizar el código duplicado.
4. MÉTODO Y ENTORNO DE TRABAJO 49<br />
Figura 4.4: Algoritmo TDD: Rojo, Ver<strong>de</strong>, Refactorizar.<br />
A partir <strong>de</strong> estos simples pasos se consigue un código en el que se reduce mucho el número <strong>de</strong><br />
<strong>de</strong>fectos introducidos, y cuyo diseño emerge a partir <strong>de</strong> las sucesivas refactorizaciones.<br />
En la figura 4.4 se pue<strong>de</strong> ver ilustrado el algoritmo <strong>de</strong> TDD don<strong>de</strong> se representan los pasos<br />
usando los colores que suelen mostrar los frameworks <strong>de</strong> pruebas. Usando la metáfora <strong>de</strong> los<br />
colores, los pasos son: rojo, ver<strong>de</strong> y refactorizar.<br />
1. El rojo representa el test escrito que falla al ejecutarse puesto que todavía no existe<br />
una implementación <strong>de</strong>l requisito a probar.<br />
2. El ver<strong>de</strong> representa que se supera el test, lo que indica que se ha escrito el código que<br />
implementa el requisito y es correcto.<br />
3. El último paso siempre es refactorizar.<br />
Es muy importante que se siga el algoritmo manteniendo el or<strong>de</strong>n y sin saltarse ningún<br />
paso. <strong>La</strong> ventaja <strong>de</strong> <strong>de</strong>finir primero los test es que se comprueban que estos fallan, pues a<br />
veces los test están mal escritos y no fallan nunca por lo que no cumplen con su función. <strong>La</strong><br />
refactorización es muy importante pues va generando un diseño emergente más sencillo y<br />
mantenible.<br />
4.1.5. Adaptación <strong>de</strong> TDD al marco <strong>de</strong> trabajo<br />
TDD es una técnica <strong>de</strong>finida <strong>de</strong>ntro <strong>de</strong> la programación extrema o XP que es una metodología<br />
ágil <strong>de</strong> <strong>de</strong>sarrollo. En el proyecto se adoptará esta técnica directamente como metodología<br />
<strong>de</strong> <strong>de</strong>sarrollo, sin usar otras técnicas <strong>de</strong>finidas en XP.<br />
El uso <strong>de</strong> TDD se complementa perfectamente con Scrum, pues cada historia lleva asociado<br />
un campo llamado cómo probarlo que sirve <strong>de</strong> base para generar los test necesarios<br />
con los que comienza el algoritmo <strong>de</strong> TDD. Al usar ese campo como base <strong>de</strong> las pruebas, se<br />
está garantizando que cuando se termina <strong>de</strong> escribir el código <strong>de</strong> una historia, siguiendo el<br />
algoritmo <strong>de</strong> TDD, se termina la historia, es <strong>de</strong>cir, que cumple con lo establecido en el campo<br />
cómo probarlo.
50 4. MÉTODO Y ENTORNO DE TRABAJO<br />
4.2. Entorno <strong>de</strong> trabajo<br />
Para po<strong>de</strong>r llevar a cabo el proyecto, durante todo el <strong>de</strong>sarrollo <strong>de</strong>l mismo se ha hecho uso<br />
<strong>de</strong> diferentes recursos software; a continuación, se comentan las más <strong>de</strong>stacables agrupadas<br />
según su tipo.<br />
4.2.1. Herramientas <strong>de</strong> <strong>de</strong>sarrollo<br />
En esta sección se nombran aquellas herramientas que se han usado para llevar a cabo el<br />
<strong>de</strong>sarrollo <strong>de</strong>l proyecto; entre ellas se encuentran las herramientas con las que se han generado<br />
directamente los artefactos software, las librerías incluidas en el proyecto, las librerías<br />
usadas para las llevar a cabo las pruebas y también el software usado para la gestión y controlar<br />
<strong>de</strong>l <strong>de</strong>sarrollo.<br />
NetBeans IDE<br />
NetBeans IDE [Orab] es un entorno <strong>de</strong> <strong>de</strong>sarrollo integrado (IDE) multiplataforma con<br />
licencia libre para <strong>de</strong>sarrollos realizados principalmente con el lenguaje <strong>de</strong> programación<br />
Java, aunque a través <strong>de</strong> sus plugins también permite ser usado con <strong>de</strong> otros lenguajes como<br />
C/C++, PHP, Ruby, etc. Gracias a la gran cantidad <strong>de</strong> plugins disponibles permite la<br />
integración con gran cantidad <strong>de</strong> aplicaciones y frameworks.<br />
Netbeans ha sido el IDE usado para el <strong>de</strong>sarrollo <strong>de</strong> todos los artefactos software <strong>de</strong>l proyecto:<br />
librería, comando y servicio web.<br />
Java Development Kit<br />
El JDK o kit <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong> Java [Oraa] es el software que proporciona las herramientas<br />
necesarias para compilar, <strong>de</strong>purar y ejecutar programas en Java.<br />
Para el <strong>de</strong>sarrollo <strong>de</strong>l proyecto se ha utilizado el JDK con versión 6.<br />
Subversion<br />
Subversion [Foub] es un sistema <strong>de</strong> control <strong>de</strong> versiones centralizado con licencia libre.<br />
Subversion se ha usado tanto para el control <strong>de</strong> versiones <strong>de</strong> los tres artefactos <strong>de</strong> software<br />
generados con el proyecto como para la documentación.<br />
OpenOffice.org SDK<br />
OpenOffice.org SDK [Orad] es un kit <strong>de</strong> <strong>de</strong>sarrollo que proporciona las librerías con las<br />
interfaces necesarias para hacer uso <strong>de</strong> las funcionalida<strong>de</strong>s <strong>de</strong> la suite ofimática OpenOffice.org<br />
<strong>de</strong>s<strong>de</strong> otras aplicaciones, y a<strong>de</strong>más, permite crear nuevos componentes o extensiones<br />
para incorporarlos a las aplicaciones que forman parte <strong>de</strong> la suite.<br />
En el proyecto se ha hecho uso <strong>de</strong> OpenOffice.org SDK, concretamente <strong>de</strong> la versión 3.2,
4. MÉTODO Y ENTORNO DE TRABAJO 51<br />
para proporcionar acceso a OpenOffice.org Calc <strong>de</strong>s<strong>de</strong> la librería creada, y así incorporar<br />
la funcionalidad necesaria para realizar las operaciones con documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
JUnit<br />
JUnit [KB] es un framework para realizar pruebas unitarias <strong>de</strong> aplicaciones escritas en<br />
Java.<br />
En el proyecto se ha usado JUnit con la versión 4.8.2, con el cual se han creado las clases<br />
y método <strong>de</strong> pruebas unitarias y <strong>de</strong> integración usados para dirigir el <strong>de</strong>sarrollo <strong>de</strong> los<br />
diferentes artefactos software creados.<br />
Mockito<br />
Mockito [Fab] es un framework para realizar pruebas con el uso <strong>de</strong> mocks y objetos espía.<br />
Un mock es un objeto sin funcionalidad que simula ser objeto <strong>de</strong> una <strong>de</strong>terminada clase,<br />
ofreciendo la posibilidad <strong>de</strong> ser programado para que frente a <strong>de</strong>terminadas condiciones<br />
tenga un cierto comportamiento, como pue<strong>de</strong> ser el caso <strong>de</strong> lanzar una excepción si se llama<br />
a un método con ciertos valores o simplemente <strong>de</strong>volver un valor concreto. Estos objetos<br />
permiten que se registre el uso que se hace <strong>de</strong> ellos para posteriormente comprobar que se ha<br />
hecho el uso esperado, comprobando los métodos invocados y los valores utilizados en las<br />
llamadas.<br />
Un objeto espía al contrario que un mock tiene la misma funcionalidad que la <strong>de</strong> cualquier<br />
otro objeto <strong>de</strong> la clase que va a espiar, pero añadiendo las funcionalida<strong>de</strong>s que proporciona<br />
un mock, es <strong>de</strong>cir, permite programar el comportamiento al realizar la invocación <strong>de</strong> ciertos<br />
métodos y mantiene un registro <strong>de</strong>l uso realizado <strong>de</strong>l objeto.<br />
Mockito se ha usado en el proyecto, concretamente la versión 1.8.5, para realizar pruebas<br />
unitarias a través <strong>de</strong> sus mocks y objetos espías que han hecho posible realizar ciertas pruebas<br />
bajo <strong>de</strong>terminadas condiciones controladas y realizar la prueba <strong>de</strong> componentes <strong>de</strong> manera<br />
aislada.<br />
PowerMock<br />
PowerMock [Jay] es un framework <strong>de</strong> pruebas que extien<strong>de</strong> las funcionalida<strong>de</strong>s <strong>de</strong> otros<br />
frameworks <strong>de</strong> mocks, a través <strong>de</strong> su cargador <strong>de</strong> clases personalizado y <strong>de</strong> la modificación<br />
<strong>de</strong>l byteco<strong>de</strong>, <strong>de</strong> manera que permite realizar la simulación <strong>de</strong> métodos estáticos y privados.<br />
PowerMock pue<strong>de</strong> ser usado con los frameworks EasyMock y Mockito.<br />
PowerMock se ha usado en el proyecto, concretamente la versión 1.4.8, para aumentar<br />
la funcionalidad <strong>de</strong> Mockito, <strong>de</strong> manera que en la pruebas unitarias fuera posible simular y
52 4. MÉTODO Y ENTORNO DE TRABAJO<br />
espiar métodos estáticos y privados.<br />
Groovy<br />
Groovy [Spr] es un lenguaje <strong>de</strong> programación interpretado e implementado sobre la plataforma<br />
Java, y que proporciona una librería con el interprete <strong>de</strong>l lenguaje y con todo lo<br />
necesario para permitir el uso <strong>de</strong> este en otras aplicaciones Java.<br />
En el proyecto se ha usado la librería <strong>de</strong> Groovy, versión 1.7.9, para incorporar funcionalida<strong>de</strong>s<br />
<strong>de</strong>l interprete <strong>de</strong>l lenguaje tanto en el comando como en el servicio web generados.<br />
JAX-WS<br />
JAX-WS [com] es un API <strong>de</strong> Java <strong>de</strong> código abierto para construir servicios web, siendo<br />
la implementación <strong>de</strong> referencia <strong>de</strong> la plataforma Java EE.<br />
JAX-WS, versión 2.2.3, se ha utilizado para crear el servicio web <strong>de</strong>l proyecto.<br />
Apache Tomcat<br />
Apache Tomcat [Fouc] es un contenedor <strong>de</strong> servlets <strong>de</strong> Java <strong>de</strong> código abierto. Apache<br />
Tomcat implementa las especificaciones <strong>de</strong> los servlets y <strong>de</strong> JavaServer Pages.<br />
En el proyecto se ha usado Apache Tomcat, versión 6.0, como contenedor <strong>de</strong> pruebas para<br />
el <strong>de</strong>spliegue <strong>de</strong>l servicio web <strong>de</strong>sarrollado.<br />
OpenOffice.org Calc<br />
OpenOffice.org Calc [Orac] es una aplicación libre <strong>de</strong> hojas <strong>de</strong> cálculo que pertenece a la<br />
suite ofimática <strong>de</strong> OpenOffice.org.<br />
En el proyecto se ha usado esta aplicación para dos propósitos diferentes, por un lado<br />
se ha usado para realizar las pruebas <strong>de</strong> la librería <strong>de</strong>sarrollada, puesto que hace uso <strong>de</strong> las<br />
funcionalida<strong>de</strong>s <strong>de</strong> Calc para realizar diferentes operaciones con documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo; y por otro lado, se ha usado como editor <strong>de</strong>l documento <strong>de</strong> hoja <strong>de</strong> cálculos con el<br />
que se ha realizado toda la planificación y gestión <strong>de</strong> proyecto.<br />
4.2.2. Lenguajes <strong>de</strong> programación<br />
En esta sección se nombran aquellos lenguajes <strong>de</strong> programación usados para el <strong>de</strong>sarrollo<br />
<strong>de</strong>l proyecto.<br />
Java<br />
Java es un lenguaje <strong>de</strong> programación <strong>de</strong> alto nivel orientado a objetos, que fue <strong>de</strong>sarrollado<br />
por James Gosling en Sun Microsystem y liberado en 1995. Java toma en su sintaxis<br />
muchos elementos <strong>de</strong> C y C++, e incorpora mecanismos para una gestión automática <strong>de</strong> la
4. MÉTODO Y ENTORNO DE TRABAJO 53<br />
memoria.<br />
<strong>La</strong>s aplicaciones Java pue<strong>de</strong>n ser multiplataforma gracias a que son compiladas en un lenguaje<br />
intermedio llamado byteco<strong>de</strong> y que es interpretado por la Máquina Virtual <strong>de</strong> Java o<br />
JVM, <strong>de</strong> manera que pue<strong>de</strong>n ejecutarse en cualquier plataforma que cuente con una implementación<br />
<strong>de</strong> JVM.<br />
Todos los artefactos software <strong>de</strong>l proyecto: la librería, el comando y el servicio web, han<br />
sido <strong>de</strong>sarrollados usando Java como lenguaje <strong>de</strong> programación.<br />
Groovy<br />
Groovy [Spr] es un lenguaje <strong>de</strong> programación, interpretado y orientado a objetos, implementado<br />
sobre la plataforma Java. Este lenguaje tiene una sintaxis muy parecida a Java, y<br />
permite utilizar tanto APIs como librerías <strong>de</strong> Java <strong>de</strong>s<strong>de</strong> los scripts; a<strong>de</strong>más, las clases <strong>de</strong><br />
Groovy pue<strong>de</strong>n ser usadas <strong>de</strong>s<strong>de</strong> aplicaciones Java, al po<strong>de</strong>r ser compiladas en byteco<strong>de</strong><br />
entendible por la Máquina Virtual <strong>de</strong> Java o JVM.<br />
Groovy ha sido usado en el proyecto para crear los scripts <strong>de</strong> funcionalidad básica que<br />
ofrecen tanto el comando como el servicio web <strong>de</strong>sarrollados.<br />
4.2.3. Herramientas <strong>de</strong> documentación<br />
En esta sección se nombran aquellas herramientas utilizadas para llevar a acabo toda la<br />
documentación <strong>de</strong>l proyecto.<br />
L A TEX<br />
L A TEX [Pro] es un sistema <strong>de</strong> composición <strong>de</strong> textos usado como estándar <strong>de</strong> facto para la<br />
publicación <strong>de</strong> documentos científicos.<br />
Para el <strong>de</strong>sarrollo <strong>de</strong> la memoria <strong>de</strong>l proyecto se ha utilizado L A TEX.<br />
Eclipse con Texlipse<br />
Eclipse [Foue] es un entorno <strong>de</strong> <strong>de</strong>sarrollo integrado o IDE multiplataforma y <strong>de</strong> código<br />
abierto para <strong>de</strong>sarrollos realizados principalmente con el lenguaje <strong>de</strong> programación Java,<br />
aunque a través <strong>de</strong> sus plugins también permite ser usado con <strong>de</strong> otros lenguajes como<br />
C/C++, PHP, etc.<br />
Texlipse [OKvLV] es un plugin <strong>de</strong> Eclipse IDE para soporte <strong>de</strong> proyectos en L A TEX.<br />
En el proyecto se ha usado Eclipse con el plugin Texlipse para el <strong>de</strong>sarrollo <strong>de</strong> la documentación<br />
en L A TEX.
54 4. MÉTODO Y ENTORNO DE TRABAJO<br />
Umbrello UML Mo<strong>de</strong>ller<br />
Umbrello UML Mo<strong>de</strong>ller [umb] es una herramienta <strong>de</strong> código abierto que permite crear<br />
diagramas UML.<br />
En el proyecto se ha usado la herramienta Umbrello para la creación <strong>de</strong> los casos <strong>de</strong> usos<br />
y el resto <strong>de</strong> diagramas UML incluidos en la documentación.<br />
Gimp<br />
Gimp [Tea] es una aplicación software para edición <strong>de</strong> imágenes digitales <strong>de</strong> código abierto.<br />
Gimp se ha utilizado en el proyecto para la edición <strong>de</strong> imágenes usadas en la documentación.<br />
Inkscape<br />
Inkscape [ink] es una aplicación libre para la generación <strong>de</strong> imágenes vectoriales. Inkscape<br />
se ha utilizado en el proyecto para la generación <strong>de</strong> imágenes usadas en la documentación.<br />
OpenOffice.org Draw<br />
OpenOffice.org Draw [ooo] es una aplicación software para la generación <strong>de</strong> imágenes<br />
perteneciente a la suite OpenOffice.org.<br />
OpenOffice.org Draw se ha utilizado en el proyecto para la generación <strong>de</strong> imágenes usadas<br />
en la documentación.<br />
4.2.4. Sistemas Operativos<br />
En esta sección se nombran los sistemas operativos usados durante el <strong>de</strong>sarrollo <strong>de</strong>l proyecto.<br />
Ubuntu GNU/Linux<br />
Para el <strong>de</strong>sarrollo <strong>de</strong>l proyecto y su documentación se ha usado el sistema operativo Ubuntu<br />
GNU/Linux compilado para la arquitectura i386.<br />
Windows Vista<br />
El sistema operativo Windows Vista, en su versión <strong>de</strong> 32 bits, ha sido utilizado únicamente<br />
para realizar las pruebas que permiten comprobar la compatibilidad con Windows <strong>de</strong> cada<br />
uno <strong>de</strong> los artefactos software generados.
Capítulo 5<br />
Resultados<br />
EN este capítulo se van a explicar los resultados obtenidos al aplicar el método <strong>de</strong> trabajo<br />
<strong>de</strong>scrito en el capítulo anterior. Para explicar los resultados el capítulo se divi<strong>de</strong><br />
en diferentes secciones, don<strong>de</strong> en la primera sección se va a explicar la fase <strong>de</strong> análisis y<br />
planificación, luego a lo largo <strong>de</strong> diferentes secciones se explicará el <strong>de</strong>sarrollo <strong>de</strong> los sprints<br />
realizados para cumplir con los objetivos <strong>de</strong>l proyecto, y por último se <strong>de</strong>dicará una sección<br />
por cada uno <strong>de</strong> los cuatro artefactos resultantes <strong>de</strong> la ejecución <strong>de</strong>l proyecto.<br />
5.1. Análisis y planificación<br />
En esta sección se explica el <strong>de</strong>sarrollo <strong>de</strong> la primera fase <strong>de</strong>l proyecto que se correspon<strong>de</strong><br />
con la fase <strong>de</strong> análisis y planificación en la cual se han realizado las siguientes tareas:<br />
1. Análisis <strong>de</strong> los requisitos u objetivos <strong>de</strong>l proyecto.<br />
2. Estudio <strong>de</strong> viabilidad <strong>de</strong> las alternativas.<br />
3. Planificación <strong>de</strong>l proyecto.<br />
A continuación, se <strong>de</strong>scribirá cada una <strong>de</strong> las tareas.<br />
5.1.1. Análisis <strong>de</strong> requisitos<br />
A partir <strong>de</strong>l análisis <strong>de</strong> los objetivos <strong>de</strong>l proyecto, ya explicados con <strong>de</strong>talle en el capítulo<br />
3, y <strong>de</strong> los requisitos establecidos por la normativa académica para proyectos fin <strong>de</strong> carrera<br />
vigente, se pue<strong>de</strong>n extraer 4 historias principales que <strong>de</strong>ben ser abordadas por el proyecto.<br />
1. Librería (API): es la librería que permite la manipulación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo, con las funcionalida<strong>de</strong>s necesarias para crear nuevos documentos, modificarlos,<br />
cambiar el formato y extraer datos.<br />
2. Comando: es un comando preparado para ejecutarse <strong>de</strong>s<strong>de</strong> un terminal que hace uso<br />
<strong>de</strong> la librería que permite la manipulación <strong>de</strong> documentos hojas <strong>de</strong> cálculo y ofrece su<br />
funcionalidad con la posibilidad <strong>de</strong> automatizarse.<br />
55
56 5. RESULTADOS<br />
3. Servicio web: es un servicio web que hace uso <strong>de</strong> la librería que permite la manipulación<br />
<strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo, ofreciendo su funcionalidad para que pueda<br />
ser usada <strong>de</strong> manera remota.<br />
4. Memoria <strong>de</strong>l proyecto: es la documentación oficial <strong>de</strong>l proyecto exigida por la normativa<br />
académica.<br />
A continuación, se van a realizar un análisis <strong>de</strong> los requisitos.<br />
Librería (API)<br />
Para analizar este requisito u objetivo y po<strong>de</strong>r i<strong>de</strong>ntificar los actores con los que <strong>de</strong>be<br />
interactuar se han generado un diagrama <strong>de</strong> casos <strong>de</strong> uso básico.<br />
En la figura 5.1 se pue<strong>de</strong> ver el diagrama <strong>de</strong> casos <strong>de</strong> uso básico. En este diagrama se<br />
pue<strong>de</strong>n distinguir dos actores que van a actuar en el escenario <strong>de</strong> la librería o API:<br />
Aplicación: es la aplicación que va a usar la librería o API <strong>de</strong> OpenSheet para po<strong>de</strong>r<br />
trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Framework o alternativa: es la alternativa que va a usar la librería o API para po<strong>de</strong>r<br />
llevar a cabo la funcionalidad con documentos <strong>de</strong> hojas <strong>de</strong> cálculo ofrecida. Es <strong>de</strong>cir,<br />
la librería va a ser una capa <strong>de</strong> abstracción <strong>de</strong> alguna <strong>de</strong> las alternativas estudiadas en<br />
el capítulo <strong>de</strong> antece<strong>de</strong>ntes.<br />
Figura 5.1: Diagrama <strong>de</strong> casos <strong>de</strong> uso básico <strong>de</strong> API<br />
A<strong>de</strong>más, se pue<strong>de</strong>n distinguir cuatro casos <strong>de</strong> uso que hacen referencia a los objetivos<br />
específicos 2, 3 y 4 que hacen referencia a las operaciones que se <strong>de</strong>ben permitir:
5. RESULTADOS 57<br />
Crear documento <strong>de</strong> hojas <strong>de</strong> cálculo: este caso <strong>de</strong> uso contempla la operación <strong>de</strong><br />
creación <strong>de</strong> nuevos documentos <strong>de</strong> hojas <strong>de</strong> cálculo para po<strong>de</strong>r trabajar con ellos, y<br />
luego po<strong>de</strong>r almacenar las modificaciones realizadas.<br />
Modificar documentos <strong>de</strong> hojas <strong>de</strong> cálculo: este caso <strong>de</strong> uso contempla las siguientes<br />
operaciones:<br />
• Inserción <strong>de</strong> datos en las distintas celdas <strong>de</strong> las hojas <strong>de</strong> cálculo <strong>de</strong>l documento.<br />
• Creación <strong>de</strong> nuevas hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un documento.<br />
• Eliminación <strong>de</strong> hojas <strong>de</strong> cálculo existentes en un documento.<br />
Extracción <strong>de</strong> datos <strong>de</strong> un documento <strong>de</strong> hojas <strong>de</strong> cálculo: este caso <strong>de</strong> uso contempla<br />
la operación <strong>de</strong> extracción <strong>de</strong> datos, tanto numéricos como <strong>de</strong> texto, <strong>de</strong> las celdas que<br />
forman parte <strong>de</strong> las distintas hojas <strong>de</strong> cálculo <strong>de</strong>l documento<br />
Convertir el formato <strong>de</strong> un documento <strong>de</strong> hojas <strong>de</strong> cálculo: este caso <strong>de</strong> uso contempla<br />
las operaciones que permiten cumplir con los objetivos 3 y 4, es <strong>de</strong>cir, permitir la conversión<br />
<strong>de</strong> un formato <strong>de</strong> documento <strong>de</strong> hojas <strong>de</strong> cálculo a otro <strong>de</strong> manera automática,<br />
y a<strong>de</strong>más la exportación a PDF.<br />
Comando y servicio web<br />
Estos elementos son las que hacen <strong>de</strong> actor como aplicación en el diagrama <strong>de</strong> casos <strong>de</strong><br />
uso <strong>de</strong> la librería, ver figura 5.1, por tanto ambos se pue<strong>de</strong>n incluir en dicho diagrama e<br />
i<strong>de</strong>ntificar los actores con los que van a interactuar. En la figura 5.2 se pue<strong>de</strong> ver el diagrama<br />
<strong>de</strong> casos <strong>de</strong> uso básico.<br />
Figura 5.2: Diagrama <strong>de</strong> casos <strong>de</strong> uso básico <strong>de</strong>l comando y servicio web<br />
A partir <strong>de</strong>l diagrama <strong>de</strong> casos <strong>de</strong> uso <strong>de</strong> la librería o API se ha i<strong>de</strong>ntificado la necesidad<br />
<strong>de</strong> usar una alternativa o framework que permita trabajar con hojas <strong>de</strong> cálculo; para ello
58 5. RESULTADOS<br />
se realizará un estudio <strong>de</strong> viabilidad <strong>de</strong> las alternativas analizadas en el capítulo <strong>de</strong> antece<strong>de</strong>ntes<br />
para seleccionar una <strong>de</strong> ellas como alternativa sobre la que se construirá la librería<br />
OpenSheet.<br />
5.1.2. Estudio <strong>de</strong> viabilidad <strong>de</strong> alternativas<br />
Para po<strong>de</strong>r seleccionar una alternativa que sirva para facilitar el trabajo <strong>de</strong> la API con<br />
documentos <strong>de</strong> hojas <strong>de</strong> cálculo y que le permita lograr sus objetivos siendo compatible con<br />
la licencia <strong>de</strong>l proyecto, ha sido necesario realizar un estudio <strong>de</strong> viabilidad <strong>de</strong> las diferentes<br />
alternativas, que a<strong>de</strong>más ha servido como documentación base para generar el capítulo <strong>de</strong><br />
antece<strong>de</strong>ntes.<br />
De entre todas las alternativas estudiadas la única que permite realizar las operaciones<br />
<strong>de</strong>finidas en los requisitos, trabajar con los formatos <strong>de</strong>seados y a<strong>de</strong>más es compatible con el<br />
tipo <strong>de</strong> licencia <strong>de</strong>l proyecto, es la <strong>de</strong> usar OpenOffice.org a través <strong>de</strong> UNO. Esta alternativa<br />
a<strong>de</strong>más <strong>de</strong> ser totalmente viable por cumplir con los requisitos <strong>de</strong> funcionalidad y licencia,<br />
gracias a la cantidad <strong>de</strong> documentación <strong>de</strong> <strong>de</strong>sarrollo y uso que existe, al gran soporte y<br />
actividad que aporta tanto la comunidad como los <strong>de</strong>sarrolladores, es la que se consi<strong>de</strong>ra la<br />
mejor alternativa para utilizar como base en la creación <strong>de</strong> la librería OpenSheet.<br />
Por tanto, la librería OpenSheet va a ofrecer una interfaz <strong>de</strong> uso sencilla que por <strong>de</strong>ntro<br />
realizará todas las operaciones necesarias para hacer uso <strong>de</strong> las funcionalida<strong>de</strong>s ofrecidas<br />
por OpenOffice.org Calc. De esta manera se aisla a las aplicaciones que usen OpenSheet<br />
<strong>de</strong> la complejidad <strong>de</strong> usar directamente las funcionalida<strong>de</strong>s <strong>de</strong> OpenOffice.org a través <strong>de</strong><br />
UNO.<br />
5.1.3. Planificación<br />
Una vez se han i<strong>de</strong>ntificado las historias principales a partir <strong>de</strong>l análisis <strong>de</strong> requisitos y<br />
se ha seleccionado la alternativa o framework que se va a utilizar para llevar a cabo las<br />
operaciones con documentos <strong>de</strong> hojas <strong>de</strong> cálculo, se pue<strong>de</strong> comenzar la planificación <strong>de</strong>l<br />
proyecto haciendo uso <strong>de</strong> Scrum.<br />
Preparación <strong>de</strong> la pila <strong>de</strong> producto<br />
Lo primero consiste en analizar las cuatro historias i<strong>de</strong>ntificadas y tratar <strong>de</strong> estimar los<br />
puntos que les correspon<strong>de</strong> a cada una, y dividirlas en subhistorias si es necesario, <strong>de</strong> manera<br />
que se complete la pila <strong>de</strong> producto inicial.<br />
<strong>La</strong>s historias son divididas en subhistorias y estimadas por el Scrum master, es <strong>de</strong>cir, por el<br />
alumno. Mientras que la prioridad o importancia <strong>de</strong> cada una, que indican el or<strong>de</strong>n en el que<br />
tienen que ser implementadas, es una tarea <strong>de</strong>l dueño <strong>de</strong>l producto, es <strong>de</strong>cir, <strong>de</strong>l director <strong>de</strong>l<br />
proyecto; aunque el Scrum master presentar un or<strong>de</strong>n que pue<strong>de</strong> ser tomado como referencia
5. RESULTADOS 59<br />
por el dueño <strong>de</strong> producto.<br />
Cuadro 5.1: Pila <strong>de</strong> producto inicial<br />
ID Nombre Descripción Estimación Importancia<br />
1 Librería<br />
(API)<br />
1.1 Crear nuevos<br />
documentos<br />
1.5 Convertir el<br />
formato <strong>de</strong>l<br />
documento<br />
1.2 Abrir documentos<br />
1.3 Modificar hojas<br />
<strong>de</strong> cálculo<br />
a un documento<br />
1.4 Insertar valores<br />
en celdas<br />
1.6 Extraer valores<br />
<strong>de</strong> celdas<br />
Librería que permite la manipulación<br />
<strong>de</strong> hojas <strong>de</strong> cálculo. Permite<br />
crear nuevos documentos, modificarlos,<br />
cambiar el formato y extraer datos.<br />
13.5 ptos 500<br />
Se <strong>de</strong>be po<strong>de</strong>r crear nuevos documentos<br />
3 ptos 500<br />
que tengan uno <strong>de</strong> los forma-<br />
tos permitidos (Excel y OO) a partir<br />
<strong>de</strong> un path (incluyendo el nombre <strong>de</strong>l<br />
mismo) y permitir guardarlo.<br />
Permitir salvar el documento con 0.5 ptos 492<br />
otro formato diferente (incluyendo<br />
PDF).<br />
Se <strong>de</strong>be po<strong>de</strong>r abrir un documento<br />
(en segundo plano) ya existente<br />
a partir <strong>de</strong> su ruta. A<strong>de</strong>más una vez<br />
abierto se <strong>de</strong>be po<strong>de</strong>r recuperar sus<br />
pestañas u hojas <strong>de</strong> cálculo.<br />
3 ptos 490<br />
Se <strong>de</strong>be po<strong>de</strong>r realizar las siguientes<br />
1 ptos 480<br />
operaciones a un documento: 1)<br />
Añadir una nueva hoja <strong>de</strong> cálculo<br />
(tanto con un nombre como sin nombre).<br />
2) Borrar una hoja <strong>de</strong> cálculo<br />
(por nombre o posición). 3) Renombrar<br />
una hoja <strong>de</strong> cálculo.<br />
Se <strong>de</strong>be permitir insertar valores <strong>de</strong> 3 ptos 470<br />
la siguiente forma: 1) Insertar un valor<br />
<strong>de</strong> una celda. 2) Insertar un grupo<br />
<strong>de</strong> valores en un rango <strong>de</strong> celdas.<br />
Se <strong>de</strong>be permitir extraer valores <strong>de</strong> la<br />
siguiente forma: 1) Extraer un valor<br />
<strong>de</strong> una celda. 2) Extraer un grupo <strong>de</strong><br />
valores <strong>de</strong> un rango <strong>de</strong> celdas.<br />
3 ptos 460
60 5. RESULTADOS<br />
ID Nombre Descripción Estimación Importancia<br />
2 Comando Comando que hace uso <strong>de</strong> la librería<br />
que permite la manipulación <strong>de</strong><br />
hojas <strong>de</strong> cálculo. Permite crear nuevos<br />
documentos, modificarlos, cambiar<br />
el formato y extraer datos.<br />
10.5 ptos 400<br />
2.1 Crear nuevos<br />
documentos<br />
2.2 Abrir documentos<br />
2.3 Modificar hojas<br />
<strong>de</strong> cálculo<br />
a un documento<br />
2.4 Insertar valores<br />
en celdas<br />
2.5 Convertir el<br />
formato <strong>de</strong>l<br />
documento<br />
2.6 Extraer valores<br />
<strong>de</strong> celdas<br />
4.6 Objetivos<br />
PCF<br />
Se <strong>de</strong>be po<strong>de</strong>r crear nuevos documentos<br />
que tengan uno <strong>de</strong> los formatos<br />
permitidos (Excel y OO) a partir<br />
<strong>de</strong> un path (incluyendo el nombre <strong>de</strong>l<br />
mismo) y permitir guardarlo.<br />
4 ptos 400<br />
Se <strong>de</strong>be po<strong>de</strong>r abrir un documento<br />
1 ptos 390<br />
(en segundo plano) ya existente<br />
a partir <strong>de</strong> su ruta. A<strong>de</strong>más una vez<br />
abierto se <strong>de</strong>be po<strong>de</strong>r recuperar sus<br />
pestañas u hojas <strong>de</strong> cálculo.<br />
Se <strong>de</strong>be po<strong>de</strong>r realizar las siguientes<br />
1 ptos 380<br />
operaciones a un documento: 1)<br />
Añadir una nueva hoja <strong>de</strong> cálculo<br />
(tanto con un nombre como sin nombre).<br />
2) Borrar una hoja <strong>de</strong> cálculo<br />
(por nombre o posición). 3) Renombrar<br />
una hoja <strong>de</strong> cálculo.<br />
Se <strong>de</strong>be permitir insertar valores <strong>de</strong> 2 ptos 370<br />
la siguiente forma: 1) Insertar un valor<br />
<strong>de</strong> una celda. 2) Insertar un grupo<br />
<strong>de</strong> valores en un rango <strong>de</strong> celdas.<br />
Permitir salvar el documento con<br />
otro formato diferente (incluyendo<br />
PDF).<br />
0.5 ptos 360<br />
Se <strong>de</strong>be permitir extraer valores <strong>de</strong> la 2 ptos 350<br />
siguiente forma: 1) Extraer un valor<br />
<strong>de</strong> una celda. 2) Extraer un grupo <strong>de</strong><br />
valores <strong>de</strong> un rango <strong>de</strong> celdas.<br />
Realizar el capítulo <strong>de</strong> objetivos <strong>de</strong>l 2 ptos 320<br />
proyecto.
5. RESULTADOS 61<br />
ID Nombre Descripción Estimación Importancia<br />
3 Servicio Web Servicio web que hace uso <strong>de</strong> la<br />
librería que permite la manipulación<br />
<strong>de</strong> hojas <strong>de</strong> cálculo. Permite<br />
crear nuevos documentos, modificarlos,<br />
cambiar el formato y extraer datos.<br />
9.5 ptos 300<br />
3.1 Crear nuevos<br />
documentos<br />
3.2 Abrir documentos<br />
3.3 Modificar hojas<br />
<strong>de</strong> cálculo<br />
a un documento<br />
3.4 Insertar valores<br />
en celdas<br />
3.5 Convertir el<br />
formato <strong>de</strong>l<br />
documento<br />
3.6 Extraer valores<br />
<strong>de</strong> celdas<br />
Se <strong>de</strong>be po<strong>de</strong>r crear nuevos documentos<br />
que tengan uno <strong>de</strong> los formatos<br />
permitidos (Excel y OO) a partir<br />
<strong>de</strong> un path (incluyendo el nombre <strong>de</strong>l<br />
mismo) y permitir guardarlo.<br />
2 ptos 300<br />
Se <strong>de</strong>be po<strong>de</strong>r abrir un documento<br />
1 ptos 290<br />
(en segundo plano) ya existente<br />
a partir <strong>de</strong> su ruta. A<strong>de</strong>más una vez<br />
abierto se <strong>de</strong>be po<strong>de</strong>r recuperar sus<br />
pestañas u hojas <strong>de</strong> cálculo.<br />
Se <strong>de</strong>be po<strong>de</strong>r realizar las siguientes<br />
1 ptos 280<br />
operaciones a un documento: 1)<br />
Añadir una nueva hoja <strong>de</strong> cálculo<br />
(tanto con un nombre como sin nombre).<br />
2) Borrar una hoja <strong>de</strong> cálculo<br />
(por nombre o posición). 3) Renombrar<br />
una hoja <strong>de</strong> cálculo.<br />
Se <strong>de</strong>be permitir insertar valores <strong>de</strong> 2 ptos 270<br />
la siguiente forma: 1) Insertar un valor<br />
<strong>de</strong> una celda. 2) Insertar un grupo<br />
<strong>de</strong> valores en un rango <strong>de</strong> celdas.<br />
Permitir salvar el documento con<br />
otro formato diferente (incluyendo<br />
PDF).<br />
0.5 ptos 260<br />
Se <strong>de</strong>be permitir extraer valores <strong>de</strong> la 2 ptos 250<br />
siguiente forma: 1) Extraer un valor<br />
<strong>de</strong> una celda. 2) Extraer un grupo <strong>de</strong><br />
valores <strong>de</strong> un rango <strong>de</strong> celdas.<br />
4 Documentación Se <strong>de</strong>be realizar la memoria <strong>de</strong>l proyecto<br />
18 ptos 200<br />
necesaria para cumplir con la<br />
normativa académica.
62 5. RESULTADOS<br />
ID Nombre Descripción Estimación Importancia<br />
4.1 Introducción Realizar el capítulo <strong>de</strong> introducción. 2 ptos 200<br />
4.2 Antece<strong>de</strong>ntes Realizar el capítulo <strong>de</strong> estudio <strong>de</strong>l estado<br />
4 ptos 190<br />
<strong>de</strong>l arte.<br />
4.5 Método <strong>de</strong> Realizar el capítulo <strong>de</strong> método <strong>de</strong> trabajo.<br />
3 ptos 160<br />
trabajo<br />
4.6 Resultados Realizar el capítulo <strong>de</strong> método <strong>de</strong> resultados.<br />
2 ptos 150<br />
4.7 Conclusiones Realizar el capítulo <strong>de</strong> método <strong>de</strong> 2 ptos 140<br />
conclusiones.<br />
4.3 Manual <strong>de</strong> Realizar un manual para uso <strong>de</strong> 2 ptos x<br />
UNO UNO.<br />
A partir <strong>de</strong> la presentación <strong>de</strong> la pila <strong>de</strong> producto con las subhistorias, el dueño <strong>de</strong> producto<br />
en función <strong>de</strong> las estimaciones ha asignado la importancia a cada historia, en la mayoría<br />
<strong>de</strong> los casos respetando el or<strong>de</strong>n inicial dado, pero en otros el or<strong>de</strong>n ha sido cambiado para<br />
po<strong>de</strong>r incluir en cada sprint el máximo número <strong>de</strong> historias.<br />
Como se pue<strong>de</strong> ver en la tabla 5.1, cada historia se ha dividido en subhistorias y se ha<br />
estimado <strong>de</strong> la siguiente manera:<br />
1. Librería (API): se ha estimado en 13.5 puntos y se ha dividido en seis subhistorias.<br />
2. Comando: se ha estimado en 10.5 puntos y se ha dividido en seis subhistorias.<br />
3. Servicio web: se ha estimado en 9.5 puntos y también se ha dividido en seis subhistorias.<br />
4. Documentación: se ha estimado en 18 puntos y se ha dividido en siete subhistorias.<br />
A<strong>de</strong>más, el dueño <strong>de</strong> producto en principio no ha asignado ningún valor a la importancia<br />
<strong>de</strong> la historia 4.3 y aunque en principio se mantiene en la pila <strong>de</strong> producto posiblemente se<br />
elimine pues la generación <strong>de</strong> un manual <strong>de</strong> UNO queda fuera <strong>de</strong> la memoria, y en todo caso<br />
sería incluido a modo <strong>de</strong> apéndice.<br />
División en sprints<br />
Una vez se tienen estimadas y priorizadas las historias se <strong>de</strong>ben dividir en sprints, puesto<br />
que el dueño <strong>de</strong> producto las ha priorizado teniendo sobre todo en cuenta el maximizar el
5. RESULTADOS 63<br />
número <strong>de</strong> historias en cada sprint, simplemente basta con ir cogiendo historias intentando<br />
que la suma <strong>de</strong> puntos estimados que<strong>de</strong> lo más cerca posible <strong>de</strong> 4.<br />
Con la pila <strong>de</strong> producto inicial, que puesto que es una metodología ágil se permite que<br />
cambie con forme se avance en el <strong>de</strong>sarrollo <strong>de</strong>l proyecto y se <strong>de</strong>tecten nuevas necesida<strong>de</strong>s,<br />
se han planificado todas las historias, excepto la 4.3, en 13 sprints:<br />
Sprint 1: Crear documentos y guardarlos<br />
Historias : 1.1, 1.5<br />
Velocidad estimada : 3.5<br />
Sprint 2: Abrir y modificaciones <strong>de</strong> hojas<br />
Historias : 1.2, 1.3<br />
Velocidad estimada : 4<br />
Sprint 3: Modificaciones <strong>de</strong> Celdas<br />
Historias : 1.4<br />
Velocidad estimada : 3<br />
Sprint 4: Extraer información <strong>de</strong> documentos<br />
Historias : 1.6<br />
Velocidad estimada : 3<br />
Sprint 5: Crear documentos con el comando<br />
Historias : 2.1<br />
Velocidad estimada : 4<br />
Sprint 6: Abrir y modificar documentos con el comando<br />
Historias : 2.2, 2.3, 2.4<br />
Velocidad estimada : 4<br />
Sprint 7: Extraer datos y cambiar formato con el comando<br />
Historias : 2.5, 2.6, 4.4<br />
Velocidad estimada : 4.5<br />
Sprint 8: Web service (crear y abrir documentos)<br />
Historias : 3.1, 3.2
64 5. RESULTADOS<br />
Velocidad estimada : 4<br />
Sprint 9: Web service (modificar documentos y conversiones <strong>de</strong> formato)<br />
Historias : 3.3, 3.4, 3.5<br />
Velocidad estimada : 3.5<br />
Sprint 10: Web service (extraer valores) y Documentación 1<br />
Historias : 3.6, 4.1<br />
Velocidad estimada : 4<br />
Sprint 11: Documentación 2<br />
Historias : 4.2<br />
Velocidad estimada : 4<br />
Sprint 12: Documentación 3<br />
Historias : 4.5<br />
Velocidad estimada : 3<br />
Sprint 13: Documentación 4<br />
Historias : 4.6, 4.7<br />
Velocidad estimada : 4<br />
Una vez se ha explicado la planificación <strong>de</strong> comienzo <strong>de</strong>l proyecto, en las siguientes secciones<br />
se <strong>de</strong>scribirá el <strong>de</strong>sarrollo <strong>de</strong> cada sprint, don<strong>de</strong> han aparecido cambios que han modificado<br />
las historias y por tanto han variado la planificación inicial en duración y en el número<br />
<strong>de</strong> sprints.<br />
5.2. Sprint 1: Creación y almacenamiento <strong>de</strong> documentos<br />
En este primer sprint las historias <strong>de</strong> producto planificadas son:<br />
Historia 1.1: Crear nuevos documentos<br />
Historia 1.5: Convertir el formato <strong>de</strong>l documento<br />
Ambas historias forman parte <strong>de</strong> la historia 1 que se correspon<strong>de</strong> con la creación <strong>de</strong> una librería<br />
o API para la manipulación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo. Por tanto como resultado<br />
<strong>de</strong> este sprint se obtendrá esa librería <strong>de</strong> la historia 1 pero con funcionalidad reducida, siendo
5. RESULTADOS 65<br />
ID Nombre Descripción Estimación Importancia Notas<br />
1.1 Crear nuevos Se <strong>de</strong>be po<strong>de</strong>r crear nuevos documentos<br />
3 ptos 500<br />
documentos<br />
que tengan uno <strong>de</strong><br />
los formatos permitidos (Excel<br />
y OO) a partir <strong>de</strong> un path (incluyendo<br />
el nombre <strong>de</strong>l mismo) y<br />
permitir guardarlo.<br />
1.5 Convertir el Permitir salvar el documento 0.5 ptos 492<br />
formato <strong>de</strong>l con otro formato diferente (incluyendo<br />
documento<br />
PDF).<br />
Cuadro 5.2: Historias añadidas al Sprint 1<br />
esta la proporcionada por cada una <strong>de</strong> las historias planificadas. <strong>La</strong> información resumen <strong>de</strong><br />
las historias planificadas se pue<strong>de</strong> ver en la tabla 5.2.<br />
A la hora <strong>de</strong> asignar las historias al sprint, se ha tenido en cuenta que coinci<strong>de</strong> con el comienzo<br />
<strong>de</strong>l proyecto y en lugar <strong>de</strong> tratar <strong>de</strong> planificar 4 puntos <strong>de</strong> historia, que es lo <strong>de</strong>finido<br />
como la carga normal, se ha aumentado la prioridad <strong>de</strong> la historia 1.5 <strong>de</strong> manera que entre<br />
en este sprint y los puntos <strong>de</strong> historia totales planificados sean 3.5.<br />
A partir <strong>de</strong> las historias planificadas se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el <strong>de</strong> proporcionar una API o librería con la funcionalidad necesaria para<br />
crear documentos <strong>de</strong> hojas <strong>de</strong> cálculo y almacenarlos.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> cada una <strong>de</strong> las historias planificadas en<br />
este sprint.<br />
5.2.1. Historia 1.1 - Crear nuevos documentos<br />
<strong>La</strong> historia 1.1 consiste en añadir a la librería la funcionalidad necesaria para crear nuevos<br />
documentos <strong>de</strong> hojas <strong>de</strong> cálculo, con uno <strong>de</strong> los formatos admitidos, y guardarlos a partir <strong>de</strong>l<br />
path con el nombre <strong>de</strong>l fichero.<br />
Esta historia se pue<strong>de</strong> dividir a su vez en dos tareas: implementar el mecanismo <strong>de</strong> comunicación<br />
con OpenOffice.org Calc, e implementar el código necesario para completar crear<br />
y guardar nuevos documentos.<br />
Mecanismo <strong>de</strong> comunicación con OpenOffice.org Calc<br />
Al ser la primera subhistoria que se implementa <strong>de</strong> la historia 1, librería (API), conlleva<br />
la tarea, ya incluida en la estimación, <strong>de</strong> implementar el mecanismo <strong>de</strong> comunicación con<br />
OpenOffice.org Calc. Esta tarea es diferente al resto <strong>de</strong> los requisitos pues no se va a usar el<br />
algoritmo <strong>de</strong> TDD para llevarla a cabo, si no que se va a implementar directamente a partir <strong>de</strong>l<br />
uso <strong>de</strong>l mecanismo <strong>de</strong> la clase Bootstrap proporcionada por el SDK <strong>de</strong> OpenOffice.org.<br />
Al usar el mecanismo <strong>de</strong> Bootstrap en GNU/Linux se han encontrado dos principales pro-
66 5. RESULTADOS<br />
blemas:<br />
1. No se encuentra el binario <strong>de</strong> soffice, y se produce el error no office executable found!.<br />
2. Una vez solucionado el problema anterior, al usarse las funciones <strong>de</strong> UNO para conectarse<br />
con OpenOffice.org Calc <strong>de</strong>ntro <strong>de</strong> la clase Bootstrap que hacen uso <strong>de</strong> librerías<br />
dinámicas, estas no se localizan y se produce el error java.lang.UnsatisfiedLinkError:<br />
createJNI at com.sun.star.lib.connections.pipe.PipeConnection.createJNI.<br />
El primer problema se produce porque la clase Bootstrap intenta crear el proceso soffice<br />
usando como directorio la ubicación <strong>de</strong>l fichero <strong>de</strong> la clase, es <strong>de</strong>cir, don<strong>de</strong> se encuentra<br />
el fichero juh.jar, y como en GNU/Linux por <strong>de</strong>fecto los jars necesarios para usar UNO no<br />
se distribuyen por <strong>de</strong>fecto con OpenOffice.org y tampoco se instalan en ese directorio, el<br />
usuario <strong>de</strong>be conocer este problema para po<strong>de</strong>r solucionarlo copiando los jars necesarios en<br />
el directorio don<strong>de</strong> se encuentre el fichero ejecutable soffice, y luego poner en el classpath<br />
este directorio para que la librería pueda encontrarlos para su uso. Esto complica bastante<br />
al usuario que no le basta sólo con conocer don<strong>de</strong> tiene el directorio don<strong>de</strong> se encuentra el<br />
ejecutable <strong>de</strong> OpenOffice.org.<br />
El segundo problema se produce porque <strong>de</strong>ntro <strong>de</strong> la clase Bootstrap una vez se ha arrancado<br />
el proceso soffice con los parámetros necesarios para conectarse a través <strong>de</strong> una tubería<br />
o pipe, al usar el método para crear una conexión <strong>de</strong>s<strong>de</strong> java, este hace uso <strong>de</strong> una librería<br />
dinámica que no se encuentra en el directorio <strong>de</strong>l jar ni en el path y esto provoca que se<br />
produzca una excepción java.lang.UnsatisfiedLinkError. Para solucionarlo el usuario <strong>de</strong>be<br />
poner al ejecutar el jar en la variable java.library.path, el directorio don<strong>de</strong> se encuentran las<br />
librerías necesarias, tal y como se pue<strong>de</strong> ver en el listado 5.1. Esto también complica todavía<br />
más el uso <strong>de</strong> la librería.<br />
-Djava.library.path=/usr/lib/ure/lib<br />
Listado 5.1: Añadiendo un directorio a Java Library Path<br />
Para dar una solución a ambos problemas encontrados, haciendo lo más transparente posible<br />
al usuario los problemas <strong>de</strong> localización <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias, se ha modificado la clase<br />
Bootstrap y se han utilizado las clases proporcionadas por el SDK para localizar el directorio<br />
<strong>de</strong> instalación, <strong>de</strong> manera que los jars necesarios se sitúan en un directorio lib junto a la librería,<br />
y <strong>de</strong> forma automática se busca correctamente la ubicación <strong>de</strong>l ejecutable <strong>de</strong> OpenOffice<br />
y se aña<strong>de</strong> el directorio <strong>de</strong> las librerías dinámicas al java library path.<br />
Los cambios realizados en la clase Bootstrap han sido los siguientes:
5. RESULTADOS 67<br />
1. Ahora el bootstrap() recupera a partir <strong>de</strong> la llamada a getPath() <strong>de</strong> la clase Installation-<br />
Fin<strong>de</strong>r 1 la ruta don<strong>de</strong> se encuentra el ejecutable <strong>de</strong> OpenOffice.org, y es esa ruta la que<br />
se usa en lugar <strong>de</strong> coger el path a la clase <strong>de</strong>l Bootstrap. En el listado 5.2 se pue<strong>de</strong> ver<br />
comentada como se obtenida la ruta antes, y a continuación se pue<strong>de</strong> ver como se usa<br />
ahora un array <strong>de</strong> objetos URL que contienen la ruta recuperada a través <strong>de</strong> la clase<br />
InstallationFin<strong>de</strong>r.<br />
2. Se ha creado una función setLibraryPath() que se llama en el método bootstrap y<br />
que resetea los valores asignados a la propiedad java.library.path <strong>de</strong> manera que le<br />
pueda asignar el directorio don<strong>de</strong> se encuentra el ejecutable y otros directorios don<strong>de</strong><br />
se pue<strong>de</strong> encontrar las librerías dinámicas necesarias.<br />
Tanto la clase Bootstrap modificada como las clases para localizar el directorio <strong>de</strong> instalación<br />
<strong>de</strong> OpenOffice.org han sido incluidas en un paquete <strong>de</strong> la librería.<br />
/* File fOffice = NativeLibraryLoa<strong>de</strong>r.getResource(<br />
Bootstrap.class.getClassLoa<strong>de</strong>r(), sOffice); */<br />
File fOffice = NativeLibraryLoa<strong>de</strong>r.getResource(loa<strong>de</strong>r, sOffice);<br />
Listado 5.2: Cambio la localización <strong>de</strong>l path <strong>de</strong>l ejecutable en la clase Bootstrap<br />
Crear nuevos documentos<br />
Para po<strong>de</strong>r llevar a cabo esta tarea se ha utilizado el algoritmo <strong>de</strong> TDD pero con la <strong>de</strong>cisión<br />
<strong>de</strong> que las pruebas no incluirán el uso <strong>de</strong> mocks u objetos que simulen el comportamiento<br />
<strong>de</strong> OpenOffice.org Calc, si no que a pesar <strong>de</strong> que se aumente un poco los tiempos se va usar<br />
directamente los objetos remotos reales.<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la tarea, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Crear un nuevo documento docNuevo.ods y guardarlo. Comprobar que existe el fichero<br />
y se pue<strong>de</strong> abrir.<br />
2. Repetir la prueba 1 con el documento docNuevo.xls.<br />
3. Repetir la prueba 1 con los documentos plantillas docPlantilla.xlt y docPlantilla.odst.<br />
4. Al abrir estos documentos <strong>de</strong>ben abrirse como cualquier otra plantilla (no <strong>de</strong>ben permitir<br />
su modificación directamente si no generar un nuevo documento).<br />
1 Esta clase viene en el SDK <strong>de</strong> UNO OpenOffice.org
68 5. RESULTADOS<br />
5. Intentar crear nuevamente el documento docNuevo.ods (<strong>de</strong>be ya existir), al intentar<br />
crear un documento ya existente <strong>de</strong>be fallar la creación <strong>de</strong>volviendo un error.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Prueba unitarias <strong>de</strong> creación <strong>de</strong> documentos para cada uno <strong>de</strong> los tipos <strong>de</strong> ficheros<br />
permitidos. A partir <strong>de</strong> la refactorización en las propias pruebas se ha creado un método<br />
createNewDocument que es el que realmente realiza las comprobaciones <strong>de</strong>jando en<br />
el resto sólo el nombre y la extensión a probar; <strong>de</strong> esta manera se evita la repetición <strong>de</strong><br />
código innecesaria.<br />
Pruebas para la exportación a PDF.<br />
Pruebas unitarias para provocar excepciones <strong>de</strong> manera que estás se incluyan en el<br />
código. Estas excepciones son cuando no se soporta la extensión <strong>de</strong>l fichero, cuando<br />
no tiene extensión o cuando se llama a exportar a PDF sin la extensión correcta.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
OpenSheetManager: es una clase que sigue el patrón factoría y que permite recuperar<br />
objetos que implementan la interfaz IOpenSheetDocument <strong>de</strong> manera transparente.<br />
IOpenSheetDocument: es la interfaz que proporciona el acceso a las funcionalida<strong>de</strong>s<br />
<strong>de</strong> un documento <strong>de</strong> hojas <strong>de</strong> cálculo. En este punto sólo se proporciona el método<br />
para close() cerrarlo.<br />
OpenSheetDocument: es la clase que representa un documento <strong>de</strong> hojas <strong>de</strong> cálculo<br />
y que por tanto hace uso <strong>de</strong> los objetos necesarios <strong>de</strong> UNO y OpenOffice.org, implementando<br />
a<strong>de</strong>más la interfaz IOpenSheetDocument.<br />
OverwriteOpenSheetDocumentException: excepción que se produce cuando se intenta<br />
crear un nuevo documento y ya existe un fichero con ese nombre.<br />
UnsupportedOpenSheetDocumentException: excepción que se produce cuando no<br />
se soporta la extensión <strong>de</strong>l fichero a crear.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.
5. RESULTADOS 69<br />
5.2.2. Historia 1.5 - Convertir el formato <strong>de</strong>l documento<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Abrir un documento en formato ods y guardarlo con el mismo nombre en diferentes<br />
formatos: xls, xlt, odst y pdf.<br />
2. Repetir la prueba 1 con los formatos permitidos.<br />
3. Abrir un documento y salvarlo en un formato no permitido, <strong>de</strong>be fallar y <strong>de</strong>volver un<br />
error.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Prueba unitarias <strong>de</strong> salvado entre los distintos tipos <strong>de</strong> ficheros permitidos. A partir<br />
<strong>de</strong> la refactorización en las propias pruebas se ha creado un método saveAsDocument<br />
que es el que realmente realiza las comprobaciones <strong>de</strong>jando en el resto el fichero <strong>de</strong><br />
origen con su extensión y el fichero al que se quiere convertir; <strong>de</strong> esta manera se evita<br />
la repetición <strong>de</strong> código innecesaria.<br />
Pruebas unitarias para provocar excepciones <strong>de</strong> manera que estás se incluyan en el<br />
código. Estas excepciones son cuando no se soporta la extensión <strong>de</strong>l fichero, cuando<br />
no tiene extensión o cuando ya existe un mismo documento con ese nombre.<br />
A partir <strong>de</strong> las pruebas anteriores se han añadido los siguientes métodos a las clases IOpenSheetDocument<br />
y a OpenSheetDocument:<br />
saveAs(String documentPath): es el método que permite almacenar el documento y<br />
también guardarlo con otro formato.<br />
exportToPDF(String documenPath): es el método que permite exportar el documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo al formato PDF.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.2.3. Resumen <strong>de</strong> sprint<br />
En el sprint se han completado las dos historias planificadas en el plazo establecido. En el<br />
gráfico <strong>de</strong> burndown, ver la figura 5.3, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.
70 5. RESULTADOS<br />
Figura 5.3: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 1<br />
En el gráfico se pue<strong>de</strong> observar el poco avance los primeros días, esto es <strong>de</strong>bido al tiempo<br />
<strong>de</strong>dicado a la resolución <strong>de</strong> los problemas encontrados en la tarea <strong>de</strong> la conexión con OpenOffice.org<br />
Calc, como se ha explicado en <strong>de</strong>talle en la historia 1.1, y la recuperación se<br />
produce una vez se han realizado los primeros tests y su refactorización, que han permitido<br />
aumentar la velocidad <strong>de</strong>l <strong>de</strong>sarrollo.<br />
En este sprint como resultado se ha obtenido una primera versión <strong>de</strong> la librería que contiene<br />
la funcionalidad <strong>de</strong> crear documentos <strong>de</strong> hojas <strong>de</strong> cálculo y guardarlos. En la figura 5.4<br />
se pue<strong>de</strong> ver el diseño <strong>de</strong> clases resultante, no se han añadido al diagrama las clases que<br />
representan excepciones para aumentar la legibilidad.<br />
5.3. Sprint 2: Apertura <strong>de</strong> documentos y modificación <strong>de</strong><br />
hojas<br />
En este sprint las historias <strong>de</strong> producto planificadas son:<br />
Historia 1.2: Abrir documentos<br />
Historia 1.3: Modificar hojas <strong>de</strong> cálculo <strong>de</strong> un documento<br />
Ambas historias forman parte <strong>de</strong> la historia 1, al igual que el sprint anterior, y por tanto<br />
como resultado <strong>de</strong> este sprint se obtendrá la librería para manipulación <strong>de</strong> documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo pero con funcionalidad reducida. <strong>La</strong> funcionalidad <strong>de</strong> la librería resultante<br />
será la <strong>de</strong>l sprint anterior más la proporcionada por cada una <strong>de</strong> las historias planificadas. <strong>La</strong><br />
información resumen <strong>de</strong> las historias planificadas se pue<strong>de</strong> ver en la tabla 5.3.
5. RESULTADOS 71<br />
Figura 5.4: Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 1<br />
En este caso se las dos tareas asignadas suman 4 puntos <strong>de</strong> historia a realizar en el sprint,<br />
que es lo que se ha consi<strong>de</strong>rado una carga normal.<br />
A partir <strong>de</strong> las historias planificadas se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el <strong>de</strong> proporcionar a la API o librería <strong>de</strong>l sprint anterior la funcionalidad<br />
necesaria para abrir documentos <strong>de</strong> hojas <strong>de</strong> cálculo, y realizar modificaciones en la hojas <strong>de</strong><br />
cálculo <strong>de</strong> los documentos.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> cada una <strong>de</strong> las historias planificadas en<br />
este sprint.<br />
5.3.1. Historia 1.2 - Abrir documentos<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Abrir un documento docExample.ods, comprobar tanto el número como el nombre <strong>de</strong><br />
sus pestañas u hojas <strong>de</strong> cálculo.<br />
2. Repetir la prueba 1 con los formatos soportados.
72 5. RESULTADOS<br />
ID Nombre Descripción Estimación Importancia Notas<br />
1.2 Abrir documentomento<br />
Se <strong>de</strong>be po<strong>de</strong>r abrir un docu-<br />
3 ptos 490<br />
(en segundo plano) ya<br />
existente a partir <strong>de</strong> su ruta.<br />
A<strong>de</strong>más una vez abierto se <strong>de</strong>be<br />
po<strong>de</strong>r recuperar sus pestañas<br />
u hojas <strong>de</strong> cálculo.<br />
1.3 Modificar hojas<br />
<strong>de</strong> cálculo<br />
a un documento<br />
Se <strong>de</strong>be po<strong>de</strong>r realizar las siguientes<br />
operaciones a un documento:<br />
1) Añadir una nueva hoja<br />
<strong>de</strong> cálculo (tanto con un nombre<br />
como sin nombre). 2) Borrar<br />
una hoja <strong>de</strong> cálculo (por nombre<br />
o posición). 3) Renombrar una<br />
hoja <strong>de</strong> cálculo.<br />
1 ptos 480<br />
Cuadro 5.3: Historias añadidas al Sprint 2<br />
3. Abrir un documento docUnknow.ods que no existe, <strong>de</strong>be fallar y <strong>de</strong>volver un error.<br />
4. Abrir un documento con una extensión no permitida, <strong>de</strong>be fallar y <strong>de</strong>volver un error.<br />
5. Recuperar una pestaña a partir <strong>de</strong> su posición y comprobar su nombre.<br />
6. Recuperar una pestaña a partir <strong>de</strong> su nombre y comprobar su nombre.<br />
7. Recuperar una pestaña a partir <strong>de</strong> una posición que no existe, <strong>de</strong>be fallar y <strong>de</strong>volver un<br />
error.<br />
8. Recuperar una pestaña a partir <strong>de</strong> un nombre que no existe, <strong>de</strong>be fallar y <strong>de</strong>volver un<br />
error.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Prueba unitarias <strong>de</strong> apertura <strong>de</strong> los distintos tipos <strong>de</strong> ficheros permitidos. A partir <strong>de</strong> la<br />
refactorización en las propias pruebas se ha creado un método openNewDocument que<br />
es el que realmente realiza las comprobaciones <strong>de</strong>jando en el resto la ruta <strong>de</strong>l fichero a<br />
abrir; <strong>de</strong> esta manera se evita la repetición <strong>de</strong> código innecesaria.<br />
Pruebas unitarias para provocar excepciones en la apertura <strong>de</strong> manera que estás se<br />
incluyan en el código. Estas excepciones son cuando no se soporta la extensión <strong>de</strong>l<br />
fichero o cuando no existe un documento con ese nombre.<br />
Pruebas unitarias para la recuperación <strong>de</strong> hojas <strong>de</strong> cálculo a partir <strong>de</strong> una posición o<br />
un nombre.
5. RESULTADOS 73<br />
Pruebas unitarias para provocar excepciones en la recuperación <strong>de</strong> hojas <strong>de</strong> cálculo al<br />
usar posiciones inválidas o al usar nombres nulos o inválidos.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
ISpreadSheet: es la interfaz que proporciona el acceso a las funcionalida<strong>de</strong>s <strong>de</strong> una<br />
hojas <strong>de</strong> cálculo. En este punto sólo se proporciona el método para getName() para<br />
obtener el nombre.<br />
SpreadSheet: es la clase que representa una hoja <strong>de</strong> cálculo y que por tanto hace uso <strong>de</strong><br />
los objetos necesarios <strong>de</strong> UNO y OpenOffice.org, implementando a<strong>de</strong>más la interfaz<br />
ISpreadSheet.<br />
LoadOpenSheetDocumentException: excepción que se produce cuando se intenta<br />
abrir un nuevo documento y no se pue<strong>de</strong> por algún error.<br />
SpreadSheetNoFoundException: excepción que se produce cuando se intenta recuperar<br />
una hoja <strong>de</strong> cálculo <strong>de</strong> un documento y no existe.<br />
A<strong>de</strong>más <strong>de</strong> los elementos <strong>de</strong> diseño nuevos, se han añadido nuevos métodos a las clases<br />
existentes:<br />
getSpreadSheetsNames(): es el método <strong>de</strong> IOpenSheetDocument que permite recuperar<br />
los nombres <strong>de</strong> todas sus hojas <strong>de</strong> cálculo en un array <strong>de</strong> ca<strong>de</strong>nas.<br />
getSpreadSheet(int pos): es el método <strong>de</strong> IOpenSheetDocument que permite recuperar<br />
una hoja <strong>de</strong> cálculo u objeto ISpreadSheet a partir <strong>de</strong> su posición.<br />
getSpreadSheet(String spreadSheetName): es el método <strong>de</strong> IOpenSheetDocument que<br />
permite recuperar una hoja <strong>de</strong> cálculo u objeto ISpreadSheet a partir <strong>de</strong> su nombre.<br />
openDocument(String documentPath): es el método <strong>de</strong> OpenSheetManager que se encarga<br />
<strong>de</strong> abrir un documento <strong>de</strong> hojas <strong>de</strong> cálculo y <strong>de</strong>volver el correspondiente objeto<br />
IOpenSheetDocument.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.3.2. Historia 1.3 - Modificar hojas <strong>de</strong> cálculo <strong>de</strong> un documento<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:
74 5. RESULTADOS<br />
1. Crear un nuevo documento y añadirle dos nuevas hojas <strong>de</strong> cálculo, una <strong>de</strong> ellas sin<br />
asignarle un nombre.<br />
2. Repetir la prueba 1 con un documento ya existente.<br />
3. Crear un nuevo documento y borrar dos pestañas, una por nombre y la otra por posición.<br />
4. Abrir un documento y borrar una pestaña por nombre y otra por posición.<br />
5. Crear un nuevo documento y renombrar una pestaña.<br />
6. Abrir un documento y renombrar una pestaña.<br />
7. Repetir las pruebas 1-6 para cada uno <strong>de</strong> los formatos permitidos.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Prueba unitarias <strong>de</strong> renombrado <strong>de</strong> hojas <strong>de</strong> cálculo para los diferentes tipos <strong>de</strong> documentos<br />
permitidos. A partir <strong>de</strong> la refactorización en las propias pruebas se ha creado<br />
un método renameSheet que es el que realmente realiza las comprobaciones <strong>de</strong>l renombrado;<br />
<strong>de</strong> esta manera se evita la repetición <strong>de</strong> código innecesaria.<br />
Pruebas unitarias para provocar excepciones en el renombrado <strong>de</strong> manera que estás se<br />
incluyan en el código. Para esto también se ha refactorizado los test obteniéndose el<br />
método renameSheetFail.<br />
Prueba unitarias para añadir y borrar hojas <strong>de</strong> cálculo a un documento, probando para<br />
los diferentes tipos <strong>de</strong> documentos permitidos. A partir <strong>de</strong> la refactorización en las propias<br />
pruebas se han creado los métodos addSheetToNewDocument y <strong>de</strong>leteSheet que<br />
son los que realmente realizan las comprobaciones evitando la repetición <strong>de</strong> código.<br />
Pruebas unitarias para provocar excepciones al añadir nuevas hojas <strong>de</strong> cálculo <strong>de</strong> manera<br />
que estás se incluyan en el código. Para esto también se ha refactorizado los test<br />
obteniéndose el método addSheetToNewDocumentMustFail.<br />
Pruebas unitarias para provocar excepciones al eliminar hojas <strong>de</strong> cálculo que no existen.<br />
A partir <strong>de</strong> las pruebas anteriores, se han añadido nuevos métodos a las clases existentes:<br />
rename(): es el método <strong>de</strong> ISpreadSheet que permite cambiar el nombre <strong>de</strong> la hoja <strong>de</strong><br />
cálculo.
5. RESULTADOS 75<br />
addSpreadSheet(): es el método <strong>de</strong> IOpenSheetDocument que permite añadir una nueva<br />
hoja <strong>de</strong> cálculo con un nombre por <strong>de</strong>fecto al documento.<br />
addSpreadSheet(String spreadSheetName): es el método <strong>de</strong> IOpenSheetDocument que<br />
permite añadir una nueva hoja <strong>de</strong> cálculo al documento con el nombre dado.<br />
<strong>de</strong>leteSpreadSheet(int pos): es el método <strong>de</strong> IOpenSheetDocument que permite borrar<br />
una hoja <strong>de</strong> cálculo <strong>de</strong>l documento a partir <strong>de</strong> su posición.<br />
<strong>de</strong>leteSpreadSheet(String spreadSheetName): es el método <strong>de</strong> IOpenSheetDocument<br />
que permite borrar una hoja <strong>de</strong> cálculo <strong>de</strong>l documento a partir <strong>de</strong> su nombre.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.3.3. Resumen <strong>de</strong> sprint<br />
En el sprint se han completado las dos historias planificadas antes <strong>de</strong>l plazo establecido.<br />
En el gráfico <strong>de</strong> burndown, ver la figura 5.5, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.<br />
Figura 5.5: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 2<br />
En el gráfico se pue<strong>de</strong> observar el avance más rápido durante los primeros días que hace<br />
que antes <strong>de</strong> lo esperado se termine con las tareas planificadas, esto es <strong>de</strong>bido a que al partir<br />
ya <strong>de</strong> métodos <strong>de</strong> pruebas y algunas <strong>de</strong> las clases <strong>de</strong> dominio, se ha podido aumentar la<br />
velocidad. Después <strong>de</strong> este terminar con las historias <strong>de</strong> este sprint se ha empezado a trabajar<br />
con la siguiente historia <strong>de</strong> la pila <strong>de</strong> producto la 1.4 insertar valores en celdas.
76 5. RESULTADOS<br />
En este sprint como resultado se ha obtenido la segunda versión <strong>de</strong> la librería que contiene<br />
la funcionalidad <strong>de</strong> abrir documentos <strong>de</strong> hojas <strong>de</strong> cálculo ya creados y modificar las hojas<br />
<strong>de</strong> cálculo <strong>de</strong> un documento. En la figura 5.6 se pue<strong>de</strong> ver el diseño <strong>de</strong> clases resultante,<br />
don<strong>de</strong> han aparecido nuevas clases y en algunos casos para las existentes se han añadido<br />
nuevos métodos, no se han añadido al diagrama las clases que representan excepciones para<br />
aumentar la legibilidad.<br />
Figura 5.6: Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 2<br />
5.4. Sprint 3: Modificación <strong>de</strong> celdas<br />
En este sprint la historia <strong>de</strong> producto planificada es:<br />
Historia 1.4: Insertar valores en celdas<br />
Esta historia forma parte <strong>de</strong> la historia 1, al igual que los sprints anteriores, y por tanto<br />
como resultado <strong>de</strong> este sprint se obtendrá la librería para manipulación <strong>de</strong> documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo pero con funcionalidad reducida. <strong>La</strong> funcionalidad <strong>de</strong> la librería resultante<br />
será la <strong>de</strong>l sprint anterior más la proporcionada por la historia planificada. En este sprint<br />
<strong>de</strong>bido a que en el anterior se terminó antes y se comenzó con esta tarea planificada, se ha<br />
completado también la tarea planificada para lo que iba a ser el siguiente sprint, por tanto la<br />
funcionalidad será a<strong>de</strong>más la <strong>de</strong> esta historia no planificada. <strong>La</strong> información resumen <strong>de</strong> la<br />
historia planificada y <strong>de</strong> la historia no planificada se pue<strong>de</strong> ver en la tabla 5.4.
5. RESULTADOS 77<br />
ID Nombre Descripción Estimación Importancia Notas<br />
1.4 Insertar valores<br />
en celdas<br />
Se <strong>de</strong>be permitir insertar valores<br />
<strong>de</strong> la siguiente forma: 1) Insertar<br />
un valor <strong>de</strong> una celda. 2) Insertar<br />
un grupo <strong>de</strong> valores en un rango<br />
<strong>de</strong> celdas.<br />
3 ptos 470<br />
1.6 Extraer valores<br />
<strong>de</strong> celdas<br />
Se <strong>de</strong>be permitir extraer valores<br />
<strong>de</strong> la siguiente forma: 1) Extraer<br />
un valor <strong>de</strong> una celda. 2) Extraer<br />
un grupo <strong>de</strong> valores <strong>de</strong> un rango<br />
<strong>de</strong> celdas.<br />
3 ptos 460<br />
Cuadro 5.4: Historias añadidas al Sprint 3<br />
En este caso la historia asignada al sprint eran 3 puntos <strong>de</strong> historia, que es menos <strong>de</strong> lo<br />
consi<strong>de</strong>rado una carga normal, el problema es que la siguiente historia a añadir eran otros<br />
son otros 3 puntos, lo que podía suponer una carga excesiva pudiendo provocar que no se<br />
llegase a completar el sprint. De manera que si se terminaba la tarea se pudiera comenzar<br />
con la siguiente sin necesidad <strong>de</strong> comprometerse a que se acabara en el mismo sprint, pero<br />
como se ha comentado antes al final esta historia se ha completado en ese tiempo.<br />
A partir <strong>de</strong> la historia planificada se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el <strong>de</strong> proporcionar a la API o librería <strong>de</strong>l sprint anterior la funcionalidad<br />
necesaria para insertar valores en las celdas <strong>de</strong> las hojas <strong>de</strong> cálculo.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> cada una <strong>de</strong> las historias <strong>de</strong>l sprint tanto<br />
la planificada como la no planificada.<br />
5.4.1. Historia 1.4 - Insertar valores en celdas<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Insertar 20 valores en celdas diferentes, celda por celda, situadas en distintas pestañas<br />
u hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un nuevo documento.<br />
2. Insertar 20 grupos <strong>de</strong> valores en rangos <strong>de</strong> celdas diferentes, situadas en distintas pestañas<br />
u hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un nuevo documento.<br />
3. Repetir las pruebas 1 y 2 con documentos ya existentes, y que tengan los diferentes<br />
formatos permitidos.<br />
4. Insertar un valor en una celda cuyo nombre no existe <strong>de</strong>ntro <strong>de</strong> una pestaña, <strong>de</strong>be<br />
<strong>de</strong>volver un error.
78 5. RESULTADOS<br />
5. Insertar valores en un rango <strong>de</strong> celdas que tiene una celda cuyo nombre no existe <strong>de</strong>ntro<br />
<strong>de</strong> una pestaña, <strong>de</strong>be <strong>de</strong>volver un error.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Pruebas unitarias <strong>de</strong> inserción <strong>de</strong> valores numéricos y ca<strong>de</strong>nas en celdas <strong>de</strong> hojas <strong>de</strong><br />
cálculo <strong>de</strong> los distintos tipos <strong>de</strong> ficheros permitidos. A partir <strong>de</strong> la refactorización en<br />
las propias pruebas se han creado los métodos insertDoubleToCell, insertStringToCell,<br />
insertDoubleToRange e insertStringToRange que son los métodos encargados <strong>de</strong> realizar<br />
las comprobaciones, <strong>de</strong>jando al resto las posiciones <strong>de</strong> celdas y los valores a<br />
insertar, <strong>de</strong> manera que se evita la repetición <strong>de</strong> código innecesaria.<br />
Pruebas unitarias para provocar excepciones en la inserción <strong>de</strong> valores en celdas al usar<br />
CellPosition inválidos o valores no permitidos. Para estás pruebas se han obtenido los<br />
siguientes métodos tras la refactorización: insertDoubleToCellFail e insertStringToCellFail.<br />
Para los rangos se ha <strong>de</strong>finido test diferentes.<br />
Pruebas unitarias para la recuperación <strong>de</strong> hojas <strong>de</strong> cálculo a partir <strong>de</strong> una posición o<br />
un nombre.<br />
Pruebas unitarias para provocar excepciones en la recuperación <strong>de</strong> hojas <strong>de</strong> cálculo al<br />
usar posiciones inválidas o al usar nombres nulos o inválidos.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
CellPosition: es el objeto que <strong>de</strong>termina la posición <strong>de</strong> una celda a través <strong>de</strong> los valores<br />
X e Y.<br />
CellNoFoundException: excepción que se produce cuando se intenta referenciar a<br />
una celda que no existe <strong>de</strong>ntro <strong>de</strong> la hoja <strong>de</strong> cálculo.<br />
A<strong>de</strong>más <strong>de</strong> los elementos <strong>de</strong> diseño nuevos, se han añadido nuevos métodos a las clases<br />
existentes:<br />
setCellValue(CellPosition position, double value): es el método <strong>de</strong> ISpreadSheet que<br />
permite insertar un valor numérico en una celda i<strong>de</strong>ntificada por su posición X e Y.<br />
setCellValue(CellPosition position, String value): es el método <strong>de</strong> ISpreadSheet que<br />
permite insertar una ca<strong>de</strong>na en una celda i<strong>de</strong>ntificada por su posición X e Y.<br />
setRangeValue(CellPosition firstCellPosition, CellPosition lastCellPosition, double value):<br />
es el método <strong>de</strong> ISpreadSheet que permite insertar en todas la celdas <strong>de</strong> un rango<br />
un valor numérico.
5. RESULTADOS 79<br />
setRangeValue(CellPosition firstCellPosition, CellPosition lastCellPosition, String value):<br />
es el método <strong>de</strong> ISpreadSheet que permite insertar en todas la celdas <strong>de</strong> un rango<br />
una ca<strong>de</strong>na.<br />
save(): es el método <strong>de</strong> IOpenSheetDocument que permite recuperar salvar los cambios<br />
realizados en un documento <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Para comprobar que la historia está completa en este caso no ha sido suficiente con las<br />
pruebas unitarias usadas en el algoritmo <strong>de</strong> TDD, si no que ha sido necesario crear una clase<br />
<strong>de</strong> pruebas a parte, y su ejecución si garantiza que los elementos creados cumplen con lo<br />
pedido. De hecho en este punto hay que <strong>de</strong>stacar que se <strong>de</strong>tectó un fallo en los rangos con la<br />
nueva clase creada para comprobar que la historia estaba completa.<br />
5.4.2. Historia 1.6 - Extraer valores <strong>de</strong> celdas<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Extraer 20 valores <strong>de</strong> celdas diferentes, celda por celda, situadas en distintas pestañas<br />
u hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un documento.<br />
2. Extraer 20 grupos <strong>de</strong> valores <strong>de</strong> rangos <strong>de</strong> celdas diferentes, situadas en distintas pestañas<br />
u hojas <strong>de</strong> cálculo <strong>de</strong>ntro <strong>de</strong> un documento.<br />
3. Repetir las pruebas 1 y 2 con documentos con documentos <strong>de</strong> los diferentes formatos<br />
permitidos.<br />
4. Extraer un valor <strong>de</strong> una celda cuyo nombre no existe <strong>de</strong>ntro <strong>de</strong> una pestaña, <strong>de</strong>be<br />
<strong>de</strong>volver un error.<br />
5. Extraer valores <strong>de</strong> un rango <strong>de</strong> celdas que tiene una celda cuyo nombre no existe <strong>de</strong>ntro<br />
<strong>de</strong> una pestaña, <strong>de</strong>be <strong>de</strong>volver un error.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Pruebas unitarias <strong>de</strong> extracción <strong>de</strong> valores numéricos y ca<strong>de</strong>nas en celdas <strong>de</strong> hojas <strong>de</strong><br />
cálculo <strong>de</strong> los distintos tipos <strong>de</strong> ficheros permitidos. A partir <strong>de</strong> la refactorización en<br />
las propias pruebas se han creado los métodos getValueFromNewDocumentCell, get-<br />
TextFromNewDocumentCell, getValuesFromNewDocumentRange, getTextsFromNew-<br />
DocumentRange y getRangeContent que son los métodos encargados <strong>de</strong> realizar las<br />
comprobaciones que se comparten en diferentes métodos <strong>de</strong> manera que se evita la<br />
repetición <strong>de</strong> código innecesaria.
80 5. RESULTADOS<br />
Pruebas unitarias para provocar excepciones en la extracción <strong>de</strong> valores en celdas al<br />
usar CellPosition inválidos o valores no permitidos.<br />
A partir <strong>de</strong> las pruebas anteriores, se han añadido nuevos métodos a las clases existentes:<br />
getCellValue(CellPosition position): es el método <strong>de</strong> ISpreadSheet que permite obtener<br />
el valor numérico contenido en la celda ubicada en la posición indicada.<br />
getCellText(CellPosition position): es el método <strong>de</strong> ISpreadSheet que permite obtener<br />
el valor <strong>de</strong> texto contenido en la celda ubicada en la posición indicada.<br />
getCellContent(CellPosition position): es el método <strong>de</strong> ISpreadSheet que permite obtener<br />
el valor contenido en la celda ubicada en la posición indicada. Este método <strong>de</strong>vuelve<br />
un tipo Object que pue<strong>de</strong> ser un String o un Double según el contenido <strong>de</strong> la<br />
celda.<br />
getRangeValues(CellPosition firstCellPosition, CellPosition lastCellPosition): es el método<br />
<strong>de</strong> ISpreadSheet que permite obtener una lista <strong>de</strong> los valores numéricos contenidos<br />
en las celdas ubicadas en el rango indicado a partir <strong>de</strong> las posiciones <strong>de</strong> las dos<br />
celdas que lo <strong>de</strong>finen.<br />
getRangeTexts(CellPosition firstCellPosition, CellPosition lastCellPosition): es el método<br />
<strong>de</strong> ISpreadSheet que permite obtener una lista <strong>de</strong> los valores <strong>de</strong> texto contenidos<br />
en las celdas ubicadas en el rango indicado a partir <strong>de</strong> las posiciones <strong>de</strong> las dos celdas<br />
que lo <strong>de</strong>finen.<br />
getRangeContent(CellPosition firstCellPosition, CellPosition lastCellPosition): es el<br />
método <strong>de</strong> ISpreadSheet que permite obtener una lista <strong>de</strong> los valores contenidos en las<br />
celdas ubicadas en el rango indicado a partir <strong>de</strong> las posiciones <strong>de</strong> las dos celdas que<br />
lo <strong>de</strong>finen. Los valores son <strong>de</strong> tipo Object pues cada valor pue<strong>de</strong> ser un String o un<br />
Double según el contenido <strong>de</strong> cada celda.<br />
Para comprobar que la historia está completa en este caso tampoco ha sido suficiente con<br />
las pruebas unitarias usadas en el algoritmo <strong>de</strong> TDD, si no que ha sido necesario añadir<br />
métodos <strong>de</strong> prueba a la clase creada para probar la historia 1.4. Por tanto su ejecución prueba<br />
las historias <strong>de</strong>l sprint.<br />
5.4.3. Resumen <strong>de</strong> sprint<br />
En el sprint se ha completado la historia planificada antes <strong>de</strong>l plazo establecido y a<strong>de</strong>más<br />
se ha completado la siguiente historia que iba a ser un sprint completo. En el gráfico <strong>de</strong><br />
burndown, ver la figura 5.7, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.
5. RESULTADOS 81<br />
Figura 5.7: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 3<br />
En el gráfico se pue<strong>de</strong> observar que se comenzaba el sprint con la historia bastante avanzada,<br />
lo que ha permitido implementar la siguiente historia, y por tanto a<strong>de</strong>lantar una semana<br />
la planificación.<br />
En este sprint se han completado todas las tareas restantes <strong>de</strong> la historia 1 y como resultado<br />
se ha obtenido la versión completa <strong>de</strong> la librería o API para trabajar con documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo. En la figura 5.8 se pue<strong>de</strong> ver el diseño <strong>de</strong> clases <strong>de</strong> la librería, no se han<br />
añadido al diagrama las clases que representan excepciones para aumentar la legibilidad. En<br />
el diagrama <strong>de</strong> clases se pue<strong>de</strong> ver que es sencillo e intuitivo el uso <strong>de</strong> la librería, es <strong>de</strong>cir, se<br />
ha simplificado mucho respecto al uso directo <strong>de</strong> OpenOffice.org a través <strong>de</strong> UNO.<br />
5.5. Sprint 4: Estudio <strong>de</strong> lenguaje script y comando<br />
En este punto se ha <strong>de</strong>tectado que los requisitos iniciales <strong>de</strong>l comando pue<strong>de</strong>n ser mejorados<br />
a través <strong>de</strong>l uso <strong>de</strong> un lenguaje script; <strong>de</strong> esta manera lo que se persigue es que cuando se<br />
ejecute el comando se le pase por parámetro un script y un fichero <strong>de</strong> datos, <strong>de</strong> manera que se<br />
pue<strong>de</strong> cambiar el fichero <strong>de</strong> datos para que el resultado <strong>de</strong>l script vaya cambiando, o cambiar<br />
la funcionalidad a través <strong>de</strong>l cambio <strong>de</strong> script. Por tanto en lugar <strong>de</strong> las seis subhistorias <strong>de</strong><br />
la historia 2, se han <strong>de</strong>finido ahora tres subhistorias repartidas en dos sprints, el 4 y el 5.<br />
En este sprint las historias <strong>de</strong> producto planificadas son:<br />
Historia 2.1: Estudio <strong>de</strong> lenguaje script<br />
Historia 2.2: Comando para ejecutar scripts
82 5. RESULTADOS<br />
Figura 5.8: Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 3<br />
Ambas historias forman parte <strong>de</strong> la historia 2, por tanto como resultado <strong>de</strong> este sprint se<br />
obtendrá el comando que a través <strong>de</strong> la librería obtenida en la historia 1 permite la manipulación<br />
<strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo. <strong>La</strong> funcionalidad <strong>de</strong>l comando como tal será<br />
completa pero no se creará, en este sprint, el script necesario para que cumpla con lo <strong>de</strong>finido<br />
en la planificación inicial. Este comando <strong>de</strong>be permitir ejecutar scripts en un lenguaje script,<br />
don<strong>de</strong> a partir <strong>de</strong> un fichero <strong>de</strong> datos realiza una inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias, permitiendo<br />
<strong>de</strong>finir tipos especiales a inyectar como listas <strong>de</strong> valores.<br />
<strong>La</strong> funcionalidad <strong>de</strong>l comando resultante será la proporcionada por cada una <strong>de</strong> las historias<br />
planificadas. <strong>La</strong> información resumen <strong>de</strong> las historias planificadas se pue<strong>de</strong> ver en la<br />
tabla 5.5.<br />
En este caso se las dos tareas asignadas suman 8 puntos <strong>de</strong> historia a realizar en el sprint,<br />
que es el doble <strong>de</strong> lo que se ha consi<strong>de</strong>rado una carga normal, por tanto este sprint se realizará<br />
en dos semanas, en realidad se podría dividir en dos sprint distintos pero puesto que<br />
la primera historia no da como resultado ningún artefacto se ha <strong>de</strong>cidido agruparlas en un<br />
mismo sprint pero con duración <strong>de</strong> dos semanas.<br />
A partir <strong>de</strong> las historias planificadas se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el estudiar un lenguaje script para usarlo en el comando y la generación <strong>de</strong>l<br />
comando.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> cada una <strong>de</strong> las historias planificadas en
5. RESULTADOS 83<br />
ID Nombre Descripción Estimación Importancia Notas<br />
2.1 Estudio <strong>de</strong> Estudiar lenguajes scripts que 3 ptos 400<br />
lenguaje<br />
script<br />
permitan <strong>de</strong>s<strong>de</strong> Java ejecutarse<br />
con diferentes ficheros <strong>de</strong> datos<br />
y permitan el uso <strong>de</strong> clases Java.<br />
2.2 Comando<br />
para ejecutar<br />
Scripts<br />
Crear el comando que permita<br />
ejecutar Scripts y que realice<br />
la inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias<br />
a partir <strong>de</strong> un fichero .properties.<br />
Debe a<strong>de</strong>más permitir indicar<br />
en el fichero tipos especiales<br />
<strong>de</strong> propieda<strong>de</strong>s: Documentos<br />
(<strong>de</strong>be crear o abrir un documento<br />
e inyectarlo a la propiedad<br />
con el nombre dado), Manager<br />
<strong>de</strong> la API, Lista <strong>de</strong> ca<strong>de</strong>nas, Números.<br />
4 ptos 390<br />
Cuadro 5.5: Historias añadidas al Sprint 4<br />
este sprint.<br />
5.5.1. Historia 2.1 - Estudio <strong>de</strong> lenguaje script<br />
En está historia no se ha aplicado la metodología TDD sino que se ha realizado más una<br />
labor <strong>de</strong> investigación con pruebas <strong>de</strong> concepto para buscar un lenguaje script que se pudiera<br />
incorporar fácilmente al comando <strong>de</strong> manipulación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Después <strong>de</strong> buscar diferentes alternativas se ha seleccionado Groovy como lenguaje a<br />
incorporar <strong>de</strong>bido a las siguientes características:<br />
Permite incorporar fácilmente en una aplicación Java el intérprete <strong>de</strong> scripts.<br />
El intérprete permite asignarle un objeto Binding para realizar asignaciones a las variables<br />
<strong>de</strong> un script que se va a interpretar.<br />
Se pue<strong>de</strong>n usar objetos Java en los scripts.<br />
<strong>La</strong> sintaxis es muy parecida a Java.<br />
Con las características <strong>de</strong> asignar valores a las variables <strong>de</strong> un script <strong>de</strong>s<strong>de</strong> fuera y la posibilidad<br />
<strong>de</strong> usar objetos Java, y con la realización <strong>de</strong> una prueba <strong>de</strong> concepto don<strong>de</strong> se le ha<br />
asignado a una variable un objeto <strong>de</strong> la API <strong>de</strong> OpenSheet, creada en con la historia 1, para<br />
trabajar con un documento <strong>de</strong> hojas <strong>de</strong> cálculo; se ha comprobado que es una alternativa<br />
válida para usar, y se ha seleccionado como lenguaje script.
84 5. RESULTADOS<br />
A partir <strong>de</strong> la prueba <strong>de</strong> uso <strong>de</strong> objetos <strong>de</strong> la API <strong>de</strong> OpenSheet en scripts <strong>de</strong> Groovy se<br />
ha <strong>de</strong>tectado que no se liberaba correctamente las conexiones abiertas con OpenOffice.org y<br />
por tanto se ha añadido un método terminate() en la clase OpenSheetManager.<br />
El ejemplo realizado como prueba <strong>de</strong> concepto es el que ha servido para validar que la<br />
historia ha sido completada según lo especificado en el campo cómo probarlo:<br />
1. Generar un pequeño ejemplo Java que ejecute un script al que se le inyecta un objeto<br />
<strong>de</strong> la API y lo use para operar con él.<br />
5.5.2. Historia 2.2 - Comando para ejecutar scripts<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Si se pasan propieda<strong>de</strong>s especiales sin el formato a<strong>de</strong>cuado se produce un fallo.<br />
2. Si se pasa un fichero <strong>de</strong> propieda<strong>de</strong>s invalido se produce un fallo.<br />
3. Realizar pruebas con cada uno <strong>de</strong> los tipos especiales especificados para el fichero <strong>de</strong><br />
datos.<br />
4. Ejecutar un fichero <strong>de</strong> script con datos válidos y comprobar que se usan los valores<br />
inyectados.<br />
Para las pruebas realizas en esta historia se ha hecho uso <strong>de</strong>l framework Mockito y PowerMock<br />
, para permitir comprobar que <strong>de</strong>ntro <strong>de</strong> un método se realizan sólo las llamadas<br />
que se <strong>de</strong>ben realizar, <strong>de</strong> manera que se <strong>de</strong>fina y al mismo tiempo se compruebe el correcto<br />
flujo <strong>de</strong>l programa, y a<strong>de</strong>más, para generar mocks u objetos que simulan el comportamiento<br />
<strong>de</strong> objetos <strong>de</strong> la API <strong>de</strong> OpenSheet, para generar objetos reales sólo en aquellos casos en los<br />
se consi<strong>de</strong>ra necesario.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Pruebas unitarias <strong>de</strong> los parámetros pasados al comando y <strong>de</strong> su comportamiento. A<br />
partir <strong>de</strong> la refactorización <strong>de</strong> las pruebas se han creado los métodos verifyInvokeShow-<br />
HelpInfo y checkSetParamsCommandInvalidParamsException que realizan las comprobaciones<br />
comunes evitando duplicar código en las pruebas, y se han creado métodos<br />
auxiliares.<br />
Pruebas unitarias para comprobar la operación <strong>de</strong> ejecución <strong>de</strong>l comando, y el control<br />
<strong>de</strong> las diferentes excepciones, don<strong>de</strong> <strong>de</strong> la refactorización <strong>de</strong> las pruebas se ha obtenido<br />
el método checkOpenSheetRunScriptException que ha permitido reducir el código en
5. RESULTADOS 85<br />
otros test en los que sólo <strong>de</strong>ben pasar un objeto <strong>de</strong> una clase <strong>de</strong> excepción e indicar si<br />
se <strong>de</strong>be invocar al método <strong>de</strong> crear el objeto que ejecutará el test.<br />
Pruebas unitarias <strong>de</strong>l comportamiento en la asignación <strong>de</strong> valores extraídos y objetos<br />
especiales (listas, objetos <strong>de</strong> la API <strong>de</strong> OpenSheet) <strong>de</strong>l fichero <strong>de</strong> datos a variables<br />
<strong>de</strong> un script <strong>de</strong> Groovy. Don<strong>de</strong> la refactorización <strong>de</strong> los tests ha generado el método<br />
checkBindingPropertiesFile.<br />
Pruebas unitarias <strong>de</strong> la ejecución <strong>de</strong> scripts <strong>de</strong> Groovy y <strong>de</strong> la recuperación <strong>de</strong> valores<br />
<strong>de</strong> variables.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
OpenSheetCommand: es el objeto que representa al comando, y el encargado <strong>de</strong> comprobar<br />
los parámetros pasados y crear los objetos necesarios para realizar la ejecución<br />
<strong>de</strong> un script <strong>de</strong> Groovy.<br />
ScriptExecuter: es el objeto encargado <strong>de</strong> ejecutar un script <strong>de</strong> Groovy y <strong>de</strong> realizar la<br />
inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias, es <strong>de</strong>cir, a partir <strong>de</strong> la lectura <strong>de</strong>l fichero <strong>de</strong> datos, obtener<br />
los valores y los objetos indicados y asignarlos a las variables <strong>de</strong>l script. También<br />
permite recuperar los valores <strong>de</strong> las variables una vez finalizada la ejecución <strong>de</strong>l script.<br />
LoadOpenSheetDataFileException: excepción que se lanza cuando hay algún problema<br />
al intentar abrir un fichero <strong>de</strong> datos.<br />
OpenSheetCommandInvalidParamsException: excepción que se lanza cuando los<br />
parámetros pasados al comando son inválidos.<br />
OpenSheetRunScriptException: excepción que se lanza cuando se produce un error<br />
al ejecutar un script <strong>de</strong> Groovy.<br />
OpenSheetPropertyFormatException: excepción que se lanza cuando en el fichero<br />
<strong>de</strong> datos alguna propiedad no tiene el formato correcto.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.5.3. Resumen <strong>de</strong> sprint<br />
En el sprint se han completado las dos historias planificadas en el plazo establecido. En el<br />
gráfico <strong>de</strong> burndown, ver la figura 5.9, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.<br />
En el gráfico se pue<strong>de</strong> observar que al comienzo <strong>de</strong> cada historia el avance es más lento y<br />
poco a poco se ha ido aumentando la velocidad hasta alcanzar el compromiso establecido.
86 5. RESULTADOS<br />
Figura 5.9: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 4<br />
En este sprint como resultado se ha obtenido la primera versión <strong>de</strong>l comando que tiene<br />
la funcionalidad <strong>de</strong> necesaria para ejecutar scripts permitiendo la inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias<br />
<strong>de</strong> las variables establecidas en el fichero <strong>de</strong> datos. Sólo falta el tener scripts en Groovy para<br />
operar. En la figura 5.10 se pue<strong>de</strong> ver el diseño <strong>de</strong> clases resultante.<br />
Figura 5.10: Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 4
5. RESULTADOS 87<br />
5.6. Sprint 5: Script genérico para el comando<br />
En este sprint la historia <strong>de</strong> producto planificada ha sido:<br />
Historia 2.3: Script Genérico<br />
Esta historia forma parte <strong>de</strong> la historia 2, al igual que el sprint anterior, pero en este caso<br />
no se obtendrá un comando con mayor funcionalidad si no un script en Groovy que permita<br />
realizar las tareas pensadas en un principio para el comando y que será el distribuido por<br />
<strong>de</strong>fecto con el mismo. <strong>La</strong> información resumen <strong>de</strong> las historia planificada se pue<strong>de</strong> ver en la<br />
tabla 5.6.<br />
ID Nombre Descripción Estimación Importancia Notas<br />
2.3 Script Genérico<br />
Crear un Script que permita: 1) 4 ptos 380 Necesita<br />
Crear un nuevo documento o<br />
tener antes<br />
abrir uno existente 2) Insertar<br />
las historias<br />
nuevas hojas <strong>de</strong> cálculo al documento.<br />
2.1 y 2.2<br />
3) Eliminar hojas <strong>de</strong><br />
cálculo al documento. 4) Insertar<br />
valores a celdas <strong>de</strong>l documentos.<br />
5) Extraer valores <strong>de</strong> las<br />
celdas <strong>de</strong>l documento y exportarlos<br />
a un fichero. 6) Guardar el<br />
documento o exportarlo a los ficheros<br />
soportados.<br />
Cuadro 5.6: Historias añadidas al Sprint 5<br />
En este caso se la historia asignada son 4 puntos <strong>de</strong> historia a realizar en el sprint, que es<br />
lo que se ha consi<strong>de</strong>rado una carga normal.<br />
A partir <strong>de</strong> la historia planificada se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el realizar un script genérico en Groovy para dotar al comando <strong>de</strong> las operaciones<br />
básicas <strong>de</strong> manipulación con hojas <strong>de</strong> cálculo cambiando sólo el fichero <strong>de</strong> datos.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> la historias planificada en este sprint.<br />
5.6.1. Historia 2.3 - Script Genérico<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
1. Crear un nuevo documento y salvarlo.<br />
2. Abrir un documento y borrar 3 hojas usando su nombre.
88 5. RESULTADOS<br />
3. Abrir un documento, añadir 3 hojas nuevas y borrar 3 hojas por posición.<br />
4. Abrir un documento, añadir 3 hojas nuevas, insertar valores a las celdas, extraer valores<br />
<strong>de</strong> las celdas (exportándolas a un fichero) y exportar el documento a PDF.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo se han realizado parte en otro<br />
script en Groovy y parte en clases <strong>de</strong> Java, y han sido las siguientes:<br />
Prueba unitarias para las diferentes operaciones básicas para tratar los valores inyectados<br />
a las variables <strong>de</strong>l script. Esto se ha comprobado a través <strong>de</strong> un script en Groovy.<br />
Pruebas unitarias para los cambios necesarios en la clase CellPosition para permitir<br />
generar objetos a partir <strong>de</strong>l nombre <strong>de</strong> la celda.<br />
Pruebas unitarias para la ejecución <strong>de</strong>l script.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
OpenSheetScript.groovy: es el script <strong>de</strong> Groovy resultante <strong>de</strong> la historia.<br />
Main: es la clase con el método main <strong>de</strong>l jar <strong>de</strong>l comando. El jar autoejecutable simplemente<br />
crea un objeto comando, le asigna los mismos parámetros que se le han pasado<br />
por línea <strong>de</strong> or<strong>de</strong>nes y ejecuta el run <strong>de</strong>l comando.<br />
CellNameException: excepción que se produce cuando se un nombre incorrecto para<br />
hacer referencia a la posición <strong>de</strong> una celda.<br />
OverwriteSpreadSheetException: excepción que se produce cuando se intenta sobreescribir<br />
una hoja <strong>de</strong> cálculo que ya existe en el documento.<br />
A<strong>de</strong>más <strong>de</strong> los elementos <strong>de</strong> diseño nuevos, se han añadido nuevos métodos a las clases<br />
existentes:<br />
CellPosition(String cellName): es un nuevo constructor para la clase CellPosition que<br />
permite crear posiciones <strong>de</strong> celda a partir <strong>de</strong> un nombre válido.<br />
equals(Object obj): se ha sobreescrito el método <strong>de</strong> comparación porque era necesario<br />
en las pruebas.<br />
containsSpreadSheet(String name): es el método <strong>de</strong> IOpenSheetDocument que indica<br />
si contiene una hoja <strong>de</strong> cálculo con ese nombre.<br />
addSpreadSheet(String spreadSheetName): se ha modificado este método <strong>de</strong> IOpenSheetDocument<br />
para que lance una excepción en el caso en el que ya exista una hoja<br />
<strong>de</strong>ntro <strong>de</strong>l documento con el nombre <strong>de</strong> la nueva hoja <strong>de</strong> cálculo que se quiere crear.
5. RESULTADOS 89<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.6.2. Resumen <strong>de</strong> sprint<br />
En el sprint se ha completado las historia con una velocidad <strong>de</strong> 2 en lugar <strong>de</strong> 4, lo que ha<br />
hecho que no se cumpla la planificación, tardando el doble <strong>de</strong> lo estimado. En el gráfico <strong>de</strong><br />
burndown, ver la figura 5.11, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.<br />
Figura 5.11: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 5<br />
En el gráfico se pue<strong>de</strong> observar que el avance ha ido muy lento durante todo el sprint lo<br />
que ha hecho que se tar<strong>de</strong> dos semanas en lugar <strong>de</strong> una. <strong>La</strong> principal causa <strong>de</strong> esto es que<br />
no se estimo correctamente la historia, pues el diseño <strong>de</strong>l script para permitir realizar todas<br />
las operaciones <strong>de</strong> inserción, modificación y extracción <strong>de</strong> datos en documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo según el fichero que se usase era complicado y ha llevado más tiempo <strong>de</strong>l previsto.<br />
A<strong>de</strong>más, el <strong>de</strong>sconocimiento <strong>de</strong> la sintaxis <strong>de</strong> Groovy, aunque sea muy parecida a Java, ha<br />
hecho que se necesite más tiempo <strong>de</strong>l esperado. Junto a todo lo anterior el <strong>de</strong>sarrollo usando<br />
el algoritmo <strong>de</strong> TDD ha resultado más difícil que en puntos anteriores, principalmente <strong>de</strong>bido<br />
a la falta <strong>de</strong> experiencia con esta metodología.<br />
En este sprint se han completado todas las tareas restantes <strong>de</strong> la historia 2 y como resultado<br />
se ha obtenido la versión completa <strong>de</strong>l comando que permite a partir <strong>de</strong> un fichero <strong>de</strong><br />
datos (un fichero .properties) y un script, realizar ejecutar el script con la inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias<br />
<strong>de</strong>l fichero <strong>de</strong> datos <strong>de</strong> manera que se pueda usar la librería o API <strong>de</strong> OpenSheet<br />
para trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo. En este caso el diagrama <strong>de</strong> clases <strong>de</strong>l
90 5. RESULTADOS<br />
comando coinci<strong>de</strong> con el <strong>de</strong>l sprint anterior, ver figura 5.10.<br />
5.7. Sprint 6: Servicio web<br />
A partir <strong>de</strong> los cambios en los requisitos iniciales <strong>de</strong>l comando, se han llevado también<br />
hasta la historia 3, el servicio web. Este a partir <strong>de</strong>l uso <strong>de</strong> la librería o API <strong>de</strong> OpenSheet <strong>de</strong>be<br />
permitir la manipulación <strong>de</strong> hojas <strong>de</strong> cálculo, basándose en el mismo funcionamiento que el<br />
comando, es <strong>de</strong>cir, <strong>de</strong>be permitir al usuario seleccionar un script, <strong>de</strong> entre los disponibles<br />
para usar con el servicio web, y a <strong>de</strong> esa selección, un fichero <strong>de</strong> datos y un documento <strong>de</strong><br />
hojas <strong>de</strong> cálculo, sólo cuando sea necesario, realizará las operaciones <strong>de</strong>l script y <strong>de</strong>volverá<br />
el documento con los cambios realizados.<br />
Aunque se ha aumentado la funcionalidad pues se hace mucho más flexible el servicio<br />
web al permitir ejecutar diferentes scripts, el número <strong>de</strong> historias se reduce <strong>de</strong> tres a dos, y<br />
la estimación pasa <strong>de</strong> 9.5 puntos <strong>de</strong> historia a 4, pues se va a reutilizar parte <strong>de</strong> las clases<br />
generadas para el comando.<br />
En este sprint las historias <strong>de</strong> producto planificadas son:<br />
Historia 3.1: Operación <strong>de</strong> listado <strong>de</strong> scripts<br />
Historia 3.2: Operación <strong>de</strong> selección y ejecución <strong>de</strong> un script sobre un documento<br />
Ambas historias forman parte <strong>de</strong> la historia 3, por tanto como resultado <strong>de</strong> este sprint se obtendrá<br />
el servicio web que a través <strong>de</strong> la librería obtenida en la historia 1 permite la manipulación<br />
<strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo. <strong>La</strong> funcionalidad <strong>de</strong>l servicio web será completada<br />
en este sprint, pues se hará uso <strong>de</strong>l script básico generado para el comando.<br />
<strong>La</strong> funcionalidad <strong>de</strong>l servicio web resultante será la proporcionada por cada una <strong>de</strong> las<br />
historias planificadas. <strong>La</strong> información resumen <strong>de</strong> las historias planificadas se pue<strong>de</strong> ver en<br />
la tabla 5.7.<br />
A partir <strong>de</strong> las historias planificadas se <strong>de</strong>fine el objetivo <strong>de</strong>l sprint. El objetivo perseguido<br />
por este sprint es el <strong>de</strong> generar el servicio web para trabajar con documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo.<br />
A continuación, se va a <strong>de</strong>tallar el <strong>de</strong>sarrollo <strong>de</strong> cada una <strong>de</strong> las historias planificadas en<br />
este sprint.<br />
5.7.1. Historia 3.1 - Operación <strong>de</strong> listado <strong>de</strong> scripts<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:
5. RESULTADOS 91<br />
ID Nombre Descripción Estimación Importancia Notas<br />
3.1 Operación<br />
<strong>de</strong> listado <strong>de</strong><br />
scripts<br />
3.2 Operación<br />
<strong>de</strong> selección<br />
y ejecución<br />
<strong>de</strong> un script<br />
sobre un<br />
documento<br />
Debe existir una operación en la<br />
que se pueda recuperar la información<br />
<strong>de</strong> todos los scripts que<br />
se pue<strong>de</strong>n utilizar y la <strong>de</strong>scripción<br />
<strong>de</strong> los mismos. A<strong>de</strong>más,<br />
<strong>de</strong>be implementarse el mecanismo<br />
necesario para que mediante<br />
configuración se pueda indicar<br />
cuales van ser los scripts permitidos<br />
para usarse y su <strong>de</strong>scripción.<br />
<strong>La</strong> operación <strong>de</strong>be recibir siempre<br />
un fichero <strong>de</strong> datos y el i<strong>de</strong>ntificador<br />
<strong>de</strong>l script a ejecutar, y<br />
<strong>de</strong> manera opcional un documento.<br />
Se ejecutará el script y se<br />
<strong>de</strong>volverá el resultado <strong>de</strong> la ejecución.<br />
1 ptos 310 Con esta operación<br />
se <strong>de</strong>be<br />
crear también<br />
el servicio<br />
web.<br />
3 ptos 300<br />
Cuadro 5.7: Historias añadidas al Sprint 6<br />
1. Configurar varios scripts con sus <strong>de</strong>scripciones.<br />
2. Recuperar la lista <strong>de</strong> scripts permitidos y comprobar que coinci<strong>de</strong> con los publicados.<br />
Para las pruebas realizas en esta historia se ha hecho uso <strong>de</strong>l framework Mockito , para<br />
permitir comprobar que <strong>de</strong>ntro <strong>de</strong> un método se realizan sólo las llamadas que se <strong>de</strong>ben realizar,<br />
<strong>de</strong> manera que se <strong>de</strong>fina y al mismo tiempo se compruebe el correcto flujo <strong>de</strong>l programa,<br />
y a<strong>de</strong>más, para generar mocks u objetos que simulan el comportamiento <strong>de</strong> objetos, como<br />
por ejemplos objetos que representan directorios o ficheros.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Pruebas unitarias <strong>de</strong> los métodos auxiliares para recuperar información <strong>de</strong> los scripts.<br />
En este caso la refactorización ha dado lugar a un método checkScriptInfoValue que<br />
permite comprobar si el objeto ScriptInfo y la información esperada coinci<strong>de</strong>n.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
OpenSheetWebService: es el objeto que representa al servicio web, y que pública los<br />
métodos que hacen <strong>de</strong> operaciones. Para su construcción se ha usado JAX-WS <br />
ScriptInfoUtils: es la clase con los métodos estáticos necesarios para po<strong>de</strong>r recuperar<br />
la información <strong>de</strong> los scripts a partir <strong>de</strong> sus ficheros.
92 5. RESULTADOS<br />
ScriptInfo: es el objeto que representa la información necesaria para usar un script: el<br />
nombre, la ruta, la <strong>de</strong>scripción, las variables que hacen referencia a ficheros <strong>de</strong> salida<br />
y la variable don<strong>de</strong> se inyecta el directorio temporal.<br />
Estos elementos creados a partir <strong>de</strong> las pruebas y la refactorización cumplen con lo especificado<br />
para <strong>de</strong>terminar que la historia está completa, para ello basta con ejecutar las pruebas<br />
usadas en el algoritmo <strong>de</strong> TDD para su implementación.<br />
5.7.2. Historia 3.2 - Operación <strong>de</strong> selección y ejecución <strong>de</strong> un script<br />
sobre un documento<br />
Para empezar a crear los test que sirven para realizar la implementación <strong>de</strong> la historia, se ha<br />
utilizado como base el campo <strong>de</strong> la historia cómo probarlo don<strong>de</strong> se especifican las pruebas<br />
que se <strong>de</strong>ben cumplir para <strong>de</strong>terminar que la historia se ha implementado correctamente:<br />
Ejecutar el script <strong>de</strong> base con las siguientes opciones:<br />
1. Enviar sólo fichero <strong>de</strong> datos y crear un documento que se <strong>de</strong>vuelva al cliente <strong>de</strong>l servicio<br />
web.<br />
2. Enviar documento sobre el que aplicar modificaciones que se salven y comprobar que<br />
el documento recibido en el cliente es el esperado.<br />
3. Enviar un documento operar sobre él y <strong>de</strong>volver el resultado <strong>de</strong> convertir dicho documento<br />
a otro formato.<br />
4. Convertir un documento enviado a formato PDF.<br />
5. Enviar un documento y extraer valores sobre él.<br />
6. Enviar un documento modificarlo y extraer valores sobre él, se <strong>de</strong>be recibir los valores<br />
extraídos y el documento modificado.<br />
Para las pruebas realizas en esta historia se ha hecho uso <strong>de</strong>l framework Mockito , para<br />
permitir comprobar que <strong>de</strong>ntro <strong>de</strong> un método se realizan sólo las llamadas que se <strong>de</strong>ben<br />
realizar, <strong>de</strong> manera que se <strong>de</strong>fina y al mismo tiempo se compruebe el correcto flujo <strong>de</strong>l<br />
programa, y a<strong>de</strong>más, para generar mocks u objetos que simulan el comportamiento <strong>de</strong> objetos<br />
<strong>de</strong> la API <strong>de</strong> OpenSheet, para generar objetos reales sólo en aquellos casos en los se consi<strong>de</strong>ra<br />
necesario.<br />
<strong>La</strong>s pruebas realizadas basadas en el campo cómo probarlo han sido las siguientes:<br />
Pruebas unitarias <strong>de</strong> los métodos auxiliares para la operación <strong>de</strong> ejecutar un script.
5. RESULTADOS 93<br />
Pruebas unitarias para establecer el comportamiento <strong>de</strong> la operación isEmpty <strong>de</strong> la<br />
clase Document, que índica si el objeto es un documento vacío.<br />
Pruebas unitarias <strong>de</strong> la ejecución <strong>de</strong> scripts, es <strong>de</strong>cir, pruebas <strong>de</strong> los parámetros pasados,<br />
<strong>de</strong>l parseo inicial <strong>de</strong> variables <strong>de</strong>l fichero <strong>de</strong> datos, y <strong>de</strong>l comportamiento en la<br />
ejecución. A partir <strong>de</strong> la refactorización <strong>de</strong> las pruebas se ha creado el método checkExecuteScriptWithDocument<br />
que realiza las comprobaciones comunes evitando duplicar<br />
código en las pruebas.<br />
Se ha cambiado las pruebas <strong>de</strong>l ScriptExecuter <strong>de</strong>l comando para cambiar el constructor<br />
y que también permita usar directamente un objeto Properties a<strong>de</strong>más <strong>de</strong> un<br />
fichero <strong>de</strong> propieda<strong>de</strong>s. Para evitar repetir código en los tests para probar con ambos<br />
constructores se ha hecho uso un mecanismo que ofrece JUnit con las anotaciones<br />
@RunWith(Parameterized.class) y @Parameters <strong>de</strong> manera que se lancen los tests dos<br />
veces cambiando un parámetro que hace que se elija un constructor primero y luego el<br />
otro, evitando así una gran repetición <strong>de</strong> código en las pruebas.<br />
A partir <strong>de</strong> las pruebas anteriores han emergido los siguientes elementos <strong>de</strong> diseño:<br />
OperationUtils: es la clase con los métodos estáticos auxiliares necesarios para po<strong>de</strong>r<br />
realizar la operación <strong>de</strong> ejecutar un script.<br />
Document: es el objeto que representa un documento o fichero binario. Este objeto es<br />
el que se usa para po<strong>de</strong>r enviar y recibir ficheros con sus nombres y extensiones, en la<br />
operación <strong>de</strong>l servicio web, para po<strong>de</strong>r trabajar con ellos según su extensión.<br />
ScriptVariable: <strong>de</strong>bido a un problema <strong>de</strong> JAX-WS para usar mapas <strong>de</strong> variables, <strong>de</strong>tectado<br />
al crear el cliente <strong>de</strong> pruebas <strong>de</strong> integración, ha sido necesario crear este tipo<br />
<strong>de</strong> objeto que representa un par clave/valor, <strong>de</strong> manera que a la operación se le pase<br />
una lista <strong>de</strong> objetos <strong>de</strong> este tipo en lugar <strong>de</strong> un mapa <strong>de</strong> variables.<br />
ExecuteScriptOperation: es el objeto que representa una operación <strong>de</strong> ejecución <strong>de</strong><br />
script. Una vez se le pasan los parámetros necesarios, parsea las variables <strong>de</strong>l fichero<br />
<strong>de</strong> datos para adaptarlas al ScriptExecuter, y se queda preparado para la ejecución <strong>de</strong>l<br />
script. Cuando se ejecuta el script se <strong>de</strong>vuelve como resultado una lista con todos los<br />
documentos a <strong>de</strong>volver.<br />
OpenSheetOperationInvalidParamsException: excepción que se lanza cuando los<br />
parámetros pasados a la operación no son válidos.<br />
OpenSheetWebServiceException: excepción genérica que se lanza cuando se produce<br />
un error en alguna operación <strong>de</strong>l servicio web. Esta operación sirve para encapsular<br />
otras excepciones y lanzarlas al cliente.
94 5. RESULTADOS<br />
A<strong>de</strong>más <strong>de</strong> los elementos <strong>de</strong> diseño nuevos, se han añadido nuevos métodos a las clases<br />
existentes:<br />
ScriptExecuter(OpenSheetManager openSheetManager, Properties properties): es un<br />
nuevo método constructor <strong>de</strong> ScriptExecuter que permite crear directamente un objeto<br />
sin necesidad <strong>de</strong> leer las variables <strong>de</strong> un ficheros .properties, facilitando su uso <strong>de</strong>s<strong>de</strong><br />
el servicio web. Para evitar la repetición <strong>de</strong> código en el nuevo constructor a partir <strong>de</strong><br />
la refactorización, ha surgido un nuevo método privado InitScriptExecuter al que llama<br />
cada constructor.<br />
setCellValue(CellPosition position, String value): es el método <strong>de</strong> ISpreadSheet que<br />
permite insertar una ca<strong>de</strong>na en una celda i<strong>de</strong>ntificada por su posición X e Y.<br />
setRangeValue(CellPosition firstCellPosition, CellPosition lastCellPosition, double value):<br />
es el método <strong>de</strong> ISpreadSheet que permite insertar en todas la celdas <strong>de</strong> un rango<br />
un valor numérico.<br />
setRangeValue(CellPosition firstCellPosition, CellPosition lastCellPosition, String value):<br />
es el método <strong>de</strong> ISpreadSheet que permite insertar en todas la celdas <strong>de</strong> un rango<br />
una ca<strong>de</strong>na.<br />
save(): es el método <strong>de</strong> IOpenSheetDocument que permite recuperar salvar los cambios<br />
realizados en un documento <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Para comprobar que los elementos creados a partir <strong>de</strong> las pruebas y la refactorización<br />
cumplen con lo especificado, en este caso ha sido necesario crear un cliente <strong>de</strong>l servicio web<br />
muy básico que llama a las dos operaciones publicadas. Gracias a estas pruebas a través <strong>de</strong><br />
un cliente se han <strong>de</strong>tectado diferentes problemas, el primero ha sido la incapacidad <strong>de</strong> JAX-<br />
WS para manejar mapas <strong>de</strong> variables, como ya se ha comentado antes, lo que ha obligado<br />
a modificar las interfaces, algunas pruebas y métodos; y a<strong>de</strong>más han aparecido problemas<br />
con el <strong>de</strong>spliegue <strong>de</strong>l servicio web en el contenedor <strong>de</strong> servlets, que se han solucionado y<br />
documentado en el manual <strong>de</strong> usuario para que si a algún usuario le suce<strong>de</strong> alguno <strong>de</strong> esos<br />
problemas sepa como resolverlos.<br />
5.7.3. Resumen <strong>de</strong> sprint<br />
En el sprint se han completado las dos historias planificadas con tres días <strong>de</strong> retraso. En el<br />
gráfico <strong>de</strong> burndown, ver la figura 5.12, se pue<strong>de</strong> ver la evolución <strong>de</strong>l mismo.<br />
En el gráfico se pue<strong>de</strong> observar que en el comienzo <strong>de</strong>l sprint se ha ido más lento <strong>de</strong> los<br />
esperado, esto es <strong>de</strong>bido a que el diseño y las pruebas para las operaciones que se han realizado<br />
estaban subestimadas, luego una vez se ha <strong>de</strong>finido como llevar a cabo las operaciones<br />
y se han ido realizando más pruebas, se ha ido aumentando la velocidad. El último repunte
5. RESULTADOS 95<br />
Figura 5.12: Gráfico <strong>de</strong> burndown <strong>de</strong>l sprint 6<br />
en la gráfica casi al final <strong>de</strong>l <strong>de</strong>sarrollo ha sido provocado por los problemas encontrados al<br />
realizar las pruebas con el cliente <strong>de</strong>l servicio web creado para validar que las historias estaban<br />
completas. Esto problemas han sido por un lado con el framework utilizado, JAX-WS, y<br />
por otro con el contenedor <strong>de</strong> servlets.<br />
En este sprint como resultado se ha obtenido el servicio web completo con sus dos operaciones.<br />
En la figura 5.13 se pue<strong>de</strong> ver el diseño <strong>de</strong> clases resultante.<br />
5.8. Sprints 7-10: Documentación<br />
En esta sección se va a resumir el <strong>de</strong>sarrollo <strong>de</strong> la ultima historia <strong>de</strong>l proyecto, la historia<br />
4 que se correspon<strong>de</strong> con la realización <strong>de</strong> la documentación o memoria <strong>de</strong>l proyecto. <strong>La</strong><br />
documentación se ha dividido en 6 subhistorias, cada correspondiente a un capítulo <strong>de</strong> la<br />
memoria, con una estimación inicial <strong>de</strong> 18 puntos planificados en 4 sprints. A continuación<br />
se va a explicar cada uno <strong>de</strong> los sprints.<br />
5.8.1. Sprint 7: Documentación 1 - Antece<strong>de</strong>ntes<br />
En este sprint se ha planificado la historia 4.2, como se pue<strong>de</strong> ver en la tabla 5.8, puesto<br />
que el dueño <strong>de</strong> producto ha dado menos prioridad a la historia 4.1 al <strong>de</strong>cidir que <strong>de</strong>be<br />
completarse una vez se tenga el resto <strong>de</strong> la memoria completada.<br />
ID Nombre Descripción Estimación Importancia Notas<br />
4.2 Antece<strong>de</strong>ntes Estudio <strong>de</strong>l estado <strong>de</strong>l arte. 4 ptos 290<br />
Cuadro 5.8: Historias añadidas al Sprint 7
96 5. RESULTADOS<br />
Figura 5.13: Diagrama <strong>de</strong> clases resultante <strong>de</strong>l sprint 6<br />
En completar la historia se ha tardado prácticamente 4 semanas en lugar <strong>de</strong> una que era lo<br />
planificado. El principal problema que ha provocado este retraso ha sido la subestimación <strong>de</strong><br />
la realización <strong>de</strong> esta historia, don<strong>de</strong> los puntos reales han sido 11, y la sobrestimación <strong>de</strong> la<br />
velocidad para realizarla que ha sido <strong>de</strong> 3 puntos por semana, en lugar <strong>de</strong> 4 pues el comienzo<br />
<strong>de</strong> la documentación siempre lleva un esfuerzo adicional, y en este caso más al no conocer<br />
L A TEX.<br />
5.8.2. Sprint 8: Documentación 2 - Objetivos y Método <strong>de</strong> Trabajo<br />
En este sprint se ha planificado las historia 4.3 y 4.4, como se pue<strong>de</strong> ver en la tabla 5.9.<br />
ID Nombre Descripción Estimación Importancia Notas<br />
4.3 Objetivos<br />
2 ptos 280<br />
PCF<br />
4.4 Método <strong>de</strong><br />
3 ptos 270<br />
trabajo<br />
Cuadro 5.9: Historias añadidas al Sprint 8<br />
Este sprint se ha completado en el tiempo planificado <strong>de</strong>bido que se ha podido aumentar<br />
el tiempo a <strong>de</strong>dicar por un lado, y por otro a que la historia 4.3 se había sobrestimado siendo<br />
su duración real 1 punto, y por tanto la velocidad real y necesaria para completar este sprint<br />
ha sido <strong>de</strong> 4 puntos.
5. RESULTADOS 97<br />
5.8.3. Sprint 9: Documentación 3 - Resultados<br />
En este sprint se ha planificado la historia 4.5 como se pue<strong>de</strong> ver en la tabla 5.10.<br />
ID Nombre Descripción Estimación Importancia Notas<br />
4.5 Resultado 5 ptos 260<br />
Cuadro 5.10: Historias añadidas al Sprint 9<br />
Esta historia también ha sido subestimada siendo su estimación real <strong>de</strong> 12 puntos, y para<br />
po<strong>de</strong>r completarla con tan sólo un retraso <strong>de</strong> 4 días, ha sido necesario gastar varios días <strong>de</strong><br />
vacaciones para aumentar el tiempo <strong>de</strong> <strong>de</strong>dicación.<br />
5.8.4. Sprint 10: Documentación 4 - Conclusiones e Introducción<br />
En este sprint se ha planificado las historia 4.6 y 4.1 como se pue<strong>de</strong> ver en la tabla 5.11.<br />
ID Nombre Descripción Estimación Importancia Notas<br />
4.6 Conclusiones 2 ptos 200<br />
4.1 Introducción 2 ptos 140<br />
Cuadro 5.11: Historias añadidas al Sprint 10<br />
Esta historia aun no se ha empezado pues correspon<strong>de</strong> justo al sprint siguiente a la conclusión<br />
<strong>de</strong>l capítulo que se está redactando, pero tras la experiencia <strong>de</strong> los tiempos y velocida<strong>de</strong>s<br />
anteriores utilizados para las diferentes subhistorias <strong>de</strong> la historia 4, parece que el tiempo real<br />
<strong>de</strong> estimación será inferior al calculado en la planificación, pasando <strong>de</strong> 4 a 2 puntos, lo que<br />
va a permitir completarlo antes <strong>de</strong> lo esperado.<br />
5.9. API OpenSheet<br />
A partir <strong>de</strong> la historia 1 y <strong>de</strong> las mejoras <strong>de</strong>tectadas durante la ejecución <strong>de</strong> los sprints<br />
<strong>de</strong> las historias 2 y 3, se ha obtenido una API para trabajar con documentos <strong>de</strong> hojas <strong>de</strong><br />
cálculo.<br />
Para su construcción se han utilizado las siguientes clases <strong>de</strong> tests:<br />
OpenSheetDocumentTest: es la clase que contiene todas las pruebas relacionadas con<br />
los documentos <strong>de</strong> hojas <strong>de</strong> cálculo, es <strong>de</strong>cir, con la interfaz que IOpenSheetDocument<br />
y la clase que la implementa OpenSheetDocument. A través <strong>de</strong> sus 97 tests se ha<br />
<strong>de</strong>finido el comportamiento que se espera que tenga cada una <strong>de</strong> las operaciones <strong>de</strong><br />
estas clases.<br />
SpreadSheetTest: es la clase que contiene todas las pruebas relacionadas con las hojas<br />
<strong>de</strong> cálculo <strong>de</strong> un documento, es <strong>de</strong>cir, con la interfaz que ISpreadSheet y la clase que
98 5. RESULTADOS<br />
la implementa SpreadSheet. A través <strong>de</strong> sus 64 tests se ha <strong>de</strong>finido el comportamiento<br />
que se espera que tenga cada una <strong>de</strong> las operaciones <strong>de</strong> estas clases.<br />
CellPositionTest: es la clase que contiene las pruebas para las operaciones que usan<br />
ca<strong>de</strong>nas como i<strong>de</strong>ntificadores <strong>de</strong> la posición <strong>de</strong> una celda y operaciones <strong>de</strong> comparación<br />
para la clase CellPositionTest. A través <strong>de</strong> sus 22 tests se ha <strong>de</strong>finido el comportamiento<br />
que se espera que tengan las operaciones probadas.<br />
Sprint3Test: es una clase usada para comprobar que una vez creada la API se cumplen<br />
con lo pedido en el sprint 3 para <strong>de</strong>mostrar la completitud <strong>de</strong> la historias planificadas<br />
en ese sprint, por tanto sus 16 test no han sido usados <strong>de</strong>ntro <strong>de</strong>l algoritmo <strong>de</strong> TDD<br />
para el diseño.<br />
Los tests diseñados hacen uso directo <strong>de</strong> OpenOffice.org Calc a través UNO, y <strong>de</strong>l sistema<br />
<strong>de</strong> ficheros, pero se aseguran antes <strong>de</strong> empezar cada test que no existe ningún fichero que<br />
pueda provocar errores en las pruebas y <strong>de</strong> restaurar todo una vez finalizan.<br />
Figura 5.14: Diagrama <strong>de</strong> clases <strong>de</strong> la API <strong>de</strong> OpenSheet<br />
<strong>La</strong> API <strong>de</strong> OpenSheet permite usar OpenOffice.org Calc <strong>de</strong> manera transparente al usuario,<br />
<strong>de</strong> manera que es la librería la que busca la instalación en la máquina y levanta una instancia<br />
<strong>de</strong>l proceso <strong>de</strong> OpenOffice.org para conectarse a él y po<strong>de</strong>r hacer uso <strong>de</strong> su funcionalidad.<br />
Para ello el <strong>de</strong>sarrollador que use OpenSheet tan sólo <strong>de</strong>be usar la factoría OpenSheetManager<br />
tanto para crear un nuevo documento como para abrir uno existente, y a través <strong>de</strong> las
5. RESULTADOS 99<br />
interfaces ofrecidas IOpenSheetDocument para los documentos e ISpreadSheet para las hojas<br />
<strong>de</strong> cálculo, realizar las operaciones ofrecidas. El diagrama <strong>de</strong> clases completo obtenido a<br />
partir <strong>de</strong> la aplicación <strong>de</strong>l algoritmo <strong>de</strong> TDD es el que se pue<strong>de</strong> ver en la figura 5.14.<br />
5.10. Comando OpenSheet<br />
A partir <strong>de</strong> la historia 2 y <strong>de</strong> las mejoras <strong>de</strong>tectadas durante la ejecución <strong>de</strong> los sprints <strong>de</strong><br />
la historia 3, se ha obtenido una comando que permite ejecutar scripts e inyectarles <strong>de</strong>pen<strong>de</strong>ncias<br />
para permitir trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Para su construcción se han utilizado las siguientes clases <strong>de</strong> tests:<br />
OpenSheetCommandTest: es la clase que contiene todas las pruebas relacionadas<br />
con la clase que representa al comando, es <strong>de</strong>cir, OpenSheetCommand. A través <strong>de</strong><br />
sus 18 tests se ha <strong>de</strong>finido el comportamiento que se espera que tenga cada una <strong>de</strong> las<br />
operaciones <strong>de</strong> esta clase.<br />
ScriptExecuterTest: es la clase que contiene todas las pruebas relacionadas con la<br />
clase encargada <strong>de</strong> ejecutar scripts <strong>de</strong> Groovy e inyectarle las <strong>de</strong>pen<strong>de</strong>ncias leidas <strong>de</strong>l<br />
fichero <strong>de</strong> datos, es <strong>de</strong>cir, con la clase ScriptExecuter. A través <strong>de</strong> sus 44 tests se ha<br />
<strong>de</strong>finido el comportamiento que se espera que tenga cada una <strong>de</strong> las operaciones <strong>de</strong><br />
esta clase.<br />
OpenSheetScriptTest: es la clase que contiene todas las pruebas relacionadas con<br />
el script genérico creado para la manipulación <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo,<br />
es <strong>de</strong>cir, OpenSheetScript.groovy. A través <strong>de</strong> sus 4 tests y el script OpenSheetUtilsTest.groovy,<br />
que contiene tests <strong>de</strong> métodos auxiliares <strong>de</strong>l script, se ha <strong>de</strong>finido el<br />
comportamiento que se espera que tenga cada una <strong>de</strong> las operaciones <strong>de</strong> este script.<br />
TestUtils: es una clase con métodos auxiliares estáticos usados para llevar a cabo alguno<br />
<strong>de</strong> los pasos necesarios en las pruebas.<br />
Los tests diseñados en algunos casos hacen uso directo <strong>de</strong> OpenOffice.org Calc a través<br />
UNO, y <strong>de</strong>l sistema <strong>de</strong> ficheros, pero siempre se aseguran antes <strong>de</strong> empezar cada test que no<br />
existe ningún fichero que pueda provocar errores en las pruebas y <strong>de</strong> restaurar todo una vez<br />
finalizan.<br />
El comando <strong>de</strong> OpenSheet permite usar la API <strong>de</strong> OpenSheet generada en la historia 1<br />
<strong>de</strong>ntro <strong>de</strong> scripts <strong>de</strong>l lenguaje Groovy. El comando permite ejecutar un script escrito en<br />
Groovy inyectándole las <strong>de</strong>pen<strong>de</strong>ncias leídas <strong>de</strong> un fichero <strong>de</strong> datos pasado por paramétro<br />
en la llamada al comando; <strong>de</strong> esta manera un mismo script se pue<strong>de</strong> reutilizar simplemente<br />
cambiando el fichero <strong>de</strong> datos. El comando al estar preparado para ejecutarse en un terminal
100 5. RESULTADOS<br />
y permitir cambiar su comportamiento según el fichero <strong>de</strong> datos, permite ser usado para<br />
realizar tareas por lotes. A<strong>de</strong>más también se pue<strong>de</strong> usar para planificar y automatizar ciertas<br />
tareas <strong>de</strong> manera sencilla a través <strong>de</strong> las herramientas que ofrecen los sistemas operativos.<br />
Para permitir realizar las operaciones <strong>de</strong> la API sin necesidad <strong>de</strong> tener que crear un script,<br />
se ha generado uno, que según el contenido <strong>de</strong>l fichero <strong>de</strong> datos realiza unas operaciones u<br />
otras, ofreciendo una gran versatilidad.<br />
El diagrama <strong>de</strong> clases completo, obtenido a partir <strong>de</strong> la aplicación <strong>de</strong>l algoritmo <strong>de</strong> TDD<br />
para las historias <strong>de</strong>l comando, es el que se pue<strong>de</strong> ver en la figura 5.15.<br />
Figura 5.15: Diagrama <strong>de</strong> clases <strong>de</strong>l Comando <strong>de</strong> OpenSheet<br />
5.11. Servicio web OpenSheet<br />
A partir <strong>de</strong> la historia 3 se ha obtenido un servicio web que permite <strong>de</strong> manera remota<br />
seleccionar y ejecutar scripts, a los que se les inyectan las <strong>de</strong>pen<strong>de</strong>ncias leídas <strong>de</strong> las propieda<strong>de</strong>s<br />
pasadas, para permitir trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo.<br />
Para su construcción se han utilizado las siguientes clases <strong>de</strong> tests:<br />
ScriptInfoUtilsTest: es la clase que contiene todas las pruebas relacionadas con los<br />
métodos auxiliares que permiten recuperar la información <strong>de</strong> los scripts. A través <strong>de</strong>
5. RESULTADOS 101<br />
sus 5 tests se ha <strong>de</strong>finido el comportamiento que se espera que tenga cada una <strong>de</strong> las<br />
operaciones usadas como base para la operación <strong>de</strong>l servicio web que <strong>de</strong>vuelve una<br />
lista <strong>de</strong> objetos ScriptInfo.<br />
OperationUtilsTest: es la clase que contiene todas las pruebas relacionadas con los<br />
métodos auxiliares que permiten realizar parte <strong>de</strong> las tareas necesarias para llevar a<br />
cabo la operación <strong>de</strong> ejecución <strong>de</strong> un script haciendo uso <strong>de</strong>l ScriptExecuter creado en<br />
la historia 2. A través <strong>de</strong> sus 9 tests se ha <strong>de</strong>finido el comportamiento que se espera<br />
que tenga cada una <strong>de</strong> las operaciones usadas como base para la operación <strong>de</strong>l servicio<br />
web.<br />
DocumentTest: es la clase que contiene todas las pruebas relacionadas con la operación<br />
que comprueba si un objeto <strong>de</strong> tipo Document es vacío. A través <strong>de</strong> sus 5 tests se<br />
ha <strong>de</strong>finido el comportamiento que <strong>de</strong>be tener dicho método.<br />
ExecuteScriptOperationTest: es la clase que contiene todas las pruebas relacionadas<br />
con las operaciones <strong>de</strong> ejecución <strong>de</strong> scripts, es <strong>de</strong>cir, con la clase ExecuteScriptOperation.<br />
A través <strong>de</strong> sus 17 tests se ha <strong>de</strong>finido el comportamiento que se espera que tenga<br />
cada una <strong>de</strong> las operaciones <strong>de</strong> estas clase.<br />
Figura 5.16: Diagrama <strong>de</strong> clases <strong>de</strong>l Servicio Web <strong>de</strong> OpenSheet<br />
Los tests diseñados en algunos casos hacen uso directo <strong>de</strong> OpenOffice.org Calc a través<br />
UNO, y <strong>de</strong>l sistema <strong>de</strong> ficheros, pero siempre se aseguran antes <strong>de</strong> empezar cada test que no
102 5. RESULTADOS<br />
existe ningún fichero que pueda provocar errores en las pruebas y <strong>de</strong> restaurar todo una vez<br />
finalizan.<br />
El servicio web <strong>de</strong> OpenSheet permite usar la API <strong>de</strong> OpenSheet generada en la historia 1<br />
<strong>de</strong>ntro <strong>de</strong> scripts <strong>de</strong>l lenguaje Groovy. Para ello es necesario configurar el directorio don<strong>de</strong> se<br />
encuentran los scripts y <strong>de</strong>finir un fichero <strong>de</strong> propieda<strong>de</strong>s con las características <strong>de</strong> los scripts.<br />
El servicio web permite la misma funcionalidad que el comando <strong>de</strong> la historia 2 pero a través<br />
<strong>de</strong> los scripts configurado para ello, así se evitan posibles problemas <strong>de</strong> seguridad.<br />
El diagrama <strong>de</strong> clases completo, obtenido a partir <strong>de</strong> la aplicación <strong>de</strong>l algoritmo <strong>de</strong> TDD<br />
para las historias <strong>de</strong>l servicio web, es el que se pue<strong>de</strong> ver en la figura 5.16.<br />
5.12. Documentación<br />
A partir <strong>de</strong> la historia 4 se ha obtenido la memoria <strong>de</strong>l proyecto que <strong>de</strong>be cumplir con la<br />
normativa académica.<br />
A<strong>de</strong>más <strong>de</strong> la memoria <strong>de</strong>l proyecto, se ha generado también la siguiente documentación<br />
a lo largo <strong>de</strong>l <strong>de</strong>sarrollo <strong>de</strong>l proyecto:<br />
Documentación <strong>de</strong> la API <strong>de</strong> OpenSheet generada con Javadoc<br />
Manual <strong>de</strong> usuario <strong>de</strong>l comando <strong>de</strong> OpenSheet.<br />
Manual <strong>de</strong> usuario <strong>de</strong>l servicio web <strong>de</strong> OpenSheet.<br />
Los manuales <strong>de</strong> usuario creados se han añadido como apéndices a la memoria <strong>de</strong>l proyecto.<br />
5.13. Estadísticas <strong>de</strong>l proyecto<br />
Para terminar con el capítulo <strong>de</strong> resultados, se van a presentar unas estadísticas <strong>de</strong>l proyecto<br />
y a comentar las diferencias entre el esfuerzo invertido y el planificado.<br />
Para medir las líneas <strong>de</strong> código o SLOC, tanto <strong>de</strong>l código <strong>de</strong> producción como <strong>de</strong>l <strong>de</strong><br />
pruebas, se ha hecho uso <strong>de</strong> la aplicación SLOCCount. Para ello se ha realizado la ejecución<br />
para medir por separado el código <strong>de</strong> producción y el código <strong>de</strong> pruebas.<br />
En la tabla 5.12 se pue<strong>de</strong> ver los resultados <strong>de</strong> la ejecución <strong>de</strong> SLOCCount con el código<br />
<strong>de</strong> producción. En dicha tabla se pue<strong>de</strong> observar entre otros datos obtenidos que el número <strong>de</strong><br />
líneas correspondientes a dicho código son 2592. A<strong>de</strong>más, en la tabla también se hace referencia<br />
a las métricas <strong>de</strong>l mo<strong>de</strong>lo COCOMO que ha generado la herramienta SLOCCount.<br />
En la tabla 5.13 se pue<strong>de</strong> ver los resultados <strong>de</strong> la ejecución <strong>de</strong> SLOCCount con el código <strong>de</strong><br />
pruebas. En dicha tabla se pue<strong>de</strong> observar entre otros datos obtenidos que el número <strong>de</strong> líneas
5. RESULTADOS 103<br />
Medida<br />
Valor<br />
Total Physical Source Lines of Co<strong>de</strong> (SLOC) 2,592<br />
Development Effort Estimate, Person-Years (Person-Months) 0.54 (6.52)<br />
(Basic COCOMO mo<strong>de</strong>l, Person-Months = 2.4 ∗ (KSLOC∗∗1.05))<br />
Schedule Estimate, Years (Months) 0.42 (5.10)<br />
(Basic COCOMO mo<strong>de</strong>l, Months = 2.5 ∗ (person-months∗∗0.38))<br />
Estimated Average Number of Developers (Effort/Schedule) 1.28<br />
Total Estimated Cost to Develop $ 73,444<br />
(average salary = $56,286/year, overhead = 2.40)<br />
Cuadro 5.12: Resultado <strong>de</strong> ejecución <strong>de</strong> SLOCCount con el código <strong>de</strong> producción<br />
correspondientes a dicho código son 4047. A<strong>de</strong>más, en la tabla también se hace referencia a<br />
las métricas <strong>de</strong>l mo<strong>de</strong>lo COCOMO que ha generado la herramienta SLOCCount.<br />
Entre las dos tablas anteriores po<strong>de</strong>mos ver que el número <strong>de</strong> líneas <strong>de</strong> codigo total entre<br />
pruebas y código <strong>de</strong> producción suman 6639, <strong>de</strong> las cuales 4047 son las referentes al<br />
código usado en los test. Esto índica que aproximadamente el 61 % <strong>de</strong> las líneas <strong>de</strong> código<br />
correspon<strong>de</strong>n a la realización <strong>de</strong> los test, es <strong>de</strong>cir, ese porcentaje correspon<strong>de</strong> al esfuerzo <strong>de</strong>l<br />
proyecto <strong>de</strong>dicado a las pruebas.<br />
Medida<br />
Valor<br />
Total Physical Source Lines of Co<strong>de</strong> (SLOC) 4,047<br />
Development Effort Estimate, Person-Years (Person-Months) 0.87 (10.42)<br />
(Basic COCOMO mo<strong>de</strong>l, Person-Months = 2.4 ∗ (KSLOC∗∗1.05))<br />
Schedule Estimate, Years (Months) 0.51 (6.09)<br />
(Basic COCOMO mo<strong>de</strong>l, Months = 2.5 ∗ (person-months∗∗0.38))<br />
Estimated Average Number of Developers (Effort/Schedule) 1.71<br />
Total Estimated Cost to Develop $ 117,255<br />
(average salary = $56,286/year, overhead = 2.40)<br />
Cuadro 5.13: Resultado <strong>de</strong> ejecución <strong>de</strong> SLOCCount con el código <strong>de</strong> pruebas<br />
Al haber usado durante el <strong>de</strong>sarrollo la metodología TDD, el esfuerzo realizado para las<br />
pruebas no sólo ha sido invertido para asegurar que funciona correctamente el código <strong>de</strong><br />
producción, si no también ha sido invertido para el diseño y estructura <strong>de</strong>l código, pues este<br />
se genera a partir <strong>de</strong> cada una <strong>de</strong> las pruebas realizadas.<br />
También hay que señalar que el código repetido se ha reducido al máximo a través <strong>de</strong> las<br />
refactorizaciones continuas que se realizan con el algoritmo <strong>de</strong> TDD, en ambos casos.<br />
El tiempo aproximado invertido en el proyecto han sido <strong>de</strong> unos 4 meses <strong>de</strong> trabajo con<br />
una media <strong>de</strong> 27 horas semanales, por tanto se han empleado 432 horas.<br />
El esfuerzo estimado en la última planificación con los cambios en los requisitos realizados<br />
es <strong>de</strong> 52.5 puntos, correspondiendo como ya se explicó, 4 puntos a 27 horas semanales. Por
104 5. RESULTADOS<br />
tanto el tiempo estimado ha sido <strong>de</strong> 354 horas.<br />
Por tanto ha habido una <strong>de</strong>sviación <strong>de</strong> 78 horas entre el tiempo real y el planificado, en<br />
puntos es una <strong>de</strong>sviación <strong>de</strong> 11.5 puntos, principalmente <strong>de</strong>bido a la subestimación que se<br />
ha hecho para la realización <strong>de</strong> la memoria <strong>de</strong>l proyecto.
Capítulo 6<br />
Conclusiones<br />
EN este capítulo se muestran los objetivos alcanzados, es <strong>de</strong>cir, se realiza un análisis<br />
<strong>de</strong> los resultados obtenidos durante el <strong>de</strong>sarrollo <strong>de</strong>l proyecto, <strong>de</strong>scritos en el anterior<br />
capítulo, y se proponen posibles mejoras y ampliaciones para <strong>de</strong>sarrollar en un futuro. A<strong>de</strong>más<br />
al final se realizará un comentario con las conclusiones personales <strong>de</strong>l autor sobre el<br />
<strong>de</strong>sarrollo <strong>de</strong>l proyecto y las metodologías utilizadas.<br />
6.1. Objetivos alcanzados<br />
Se va a analizar cada uno <strong>de</strong> los objetivos marcados al comienzo <strong>de</strong>l proyecto y cómo se<br />
han cumplido.<br />
Objetivo general: El objetivo general ha sido ampliamente cubierto a través <strong>de</strong> los<br />
tres artefactos software generados: la API o librería, el comando y el servicio web;<br />
pues todos ellos proporcionan un mecanismo para insertar y extraer datos <strong>de</strong> un documento<br />
<strong>de</strong> hojas <strong>de</strong> cálculo soportando los principales formatos <strong>de</strong>l mercado, tanto <strong>de</strong><br />
Microsoft Excel como <strong>de</strong> OpenOffice.org.<br />
Objetivo específico 1: Los formatos <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo permitidos por<br />
los artefactos software generados son: xls, xlt, xlsx, ods y ots. Por tanto se ha cumplido<br />
con el objetivo, y cualquier otro formato ha sido consi<strong>de</strong>rado fuera <strong>de</strong>l alcance <strong>de</strong>l<br />
proyecto y por tanto tratado como un formato no válido.<br />
Objetivo específico 2: <strong>La</strong>s operaciones con documentos <strong>de</strong> hojas <strong>de</strong> cálculo establecidas<br />
por este objetivo también se cumplen por los tres artefactos software creados. <strong>La</strong>s<br />
operaciones son:<br />
1. Creación y apertura <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo. Estas operaciones se<br />
realizan <strong>de</strong> manera sencilla al i<strong>de</strong>ntificarse automáticamente el formato <strong>de</strong>l documento<br />
usando la extensión <strong>de</strong>l fichero.<br />
2. Extracción e inserción <strong>de</strong> datos en celdas. Estas operaciones se pue<strong>de</strong>n realizar<br />
<strong>de</strong> manera que se diferencia el tipo <strong>de</strong> datos (numéricos o texto) a insertar en la<br />
105
106 6. CONCLUSIONES<br />
celda, y a<strong>de</strong>más se ofrece la posibilidad <strong>de</strong> llevar a cabo dichas operaciones con<br />
rangos <strong>de</strong> celdas.<br />
3. Creación y eliminación <strong>de</strong> hojas <strong>de</strong> cálculo. Nuevamente estas operaciones se<br />
permiten tanto en la API como en el comando y en el servicio web, ofreciendo<br />
la posibilidad <strong>de</strong> referenciar a las hojas con las que se quiere operar usando el<br />
nombre o la posición.<br />
Objetivo específico 3: Se permiten realizar operaciones <strong>de</strong> salvado con la posibilidad<br />
<strong>de</strong> realizar conversiones <strong>de</strong> formato, entre los formatos fijados como válidos por el<br />
objetivo 2, en cada uno <strong>de</strong> los artefactos software generados. Para ello simplemente<br />
es necesario cambiar la extensión <strong>de</strong>l fichero al guardar el documento, <strong>de</strong> esta manera<br />
toda la conversión se realiza <strong>de</strong> manera automática y transparente al usuario.<br />
Objetivo específico 4: <strong>La</strong> exportación <strong>de</strong> un documento al formato PDF se permite en<br />
la API a través <strong>de</strong> una operación específica, y también se soporta en el comando y el<br />
servicio web.<br />
Objetivo específico 5: Al utilizar Java y OpenOffice.org todos los artefactos generados<br />
son multiplataforma, sin diferencia <strong>de</strong> uso para el <strong>de</strong>sarrollador en caso <strong>de</strong> usar la API<br />
o para el usuario si usa el comando o el servicio web. Sólo hay que tener en cuenta una<br />
<strong>de</strong>pen<strong>de</strong>ncia que en sistemas GNU/Linux no se tiene y si en sistemas Windows, y es<br />
que es necesario tener una dll que permite acce<strong>de</strong>r al registro para buscar el directorio<br />
<strong>de</strong> instalación OpenOffice.org; no obstante, esta dll se distribuirá siempre por <strong>de</strong>fecto<br />
sea cual sea la plataforma a utilizar.<br />
Objetivo específico 6: El API <strong>de</strong> OpenSheet generada cumple con este objetivo, y<br />
a<strong>de</strong>más su incorporación en las otras dos aplicaciones creadas, comando y servicio<br />
web, validan su uso en otras aplicaciones y proyectos.<br />
Objetivo específico 7: El comando generado está preparado para ser ejecutado <strong>de</strong>s<strong>de</strong><br />
un terminal y no sólo permite hacer uso <strong>de</strong> las operaciones <strong>de</strong> la API a través <strong>de</strong>l<br />
script básico proporcionado, si no que permite utilizarse para múltiples propósitos,<br />
para ello basta con ampliar su funcionalidad simplemente creando un script escrito<br />
en Groovy, y aprovechando sus capacida<strong>de</strong>s <strong>de</strong> inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias <strong>de</strong>s<strong>de</strong> un<br />
fichero .properties <strong>de</strong> datos.<br />
Objetivo específico 8: El servicio web generado no sólo ofrece las funcionalida<strong>de</strong>s<br />
<strong>de</strong> la librería <strong>de</strong> manera remota, si no que al igual que el comando, permite ampliar<br />
su funcionalidad a través <strong>de</strong> scripts escritos en Groovy y registrados. De esta manera<br />
un usuario pue<strong>de</strong> seleccionar que script <strong>de</strong>sea utilizar y enviar una lista <strong>de</strong> variables<br />
que serán inyectadas como <strong>de</strong>pen<strong>de</strong>ncias a dicho script, para una vez finalizada la<br />
ejecución <strong>de</strong>volver los ficheros resultantes.
6. CONCLUSIONES 107<br />
Como se pue<strong>de</strong> ver se ha cumplido ampliamente tanto con el objetivo general como con<br />
cada uno <strong>de</strong> los ocho objetivos específicos marcados al comienzo <strong>de</strong>l proyecto.<br />
6.2. Posibles mejoras y ampliaciones<br />
Aunque en la sección anterior se ha visto que se ha cumplido ampliamente con los objetivos<br />
marcados al inicio <strong>de</strong>l proyecto, durante el <strong>de</strong>sarrollo <strong>de</strong>l mismo se han <strong>de</strong>tectado posibles<br />
mejoras y ampliaciones <strong>de</strong> funcionalidad que no han sido abordadas por estar fuera <strong>de</strong>l<br />
alcance <strong>de</strong>l proyecto, pero que son ahora propuestas como posibles <strong>de</strong>sarrollos futuros.<br />
<strong>La</strong>s posibles mejoras y ampliaciones <strong>de</strong>tectadas han sido las siguientes:<br />
6.2.1. Uso <strong>de</strong> OpenOffice.org remoto<br />
Actualmente la API o librería OpenSheet, y por tanto las aplicaciones que la usan, necesitan<br />
que en la máquina don<strong>de</strong> se vayan a utilizar esté instalada la suite ofimática OpenOffice.org.<br />
Una <strong>de</strong> las posibilida<strong>de</strong>s que permite la alternativa <strong>de</strong> usar OpenOffice.org, a través<br />
<strong>de</strong> UNO, es la <strong>de</strong> conectarse por socket a un proceso remoto y hacer uso <strong>de</strong> sus funcionalida<strong>de</strong>s<br />
sin necesidad <strong>de</strong> tener instalada la suite en la máquina local don<strong>de</strong> se está ejecutando la<br />
aplicación que la va a usar.<br />
Para permitir usar la API sin necesidad <strong>de</strong> tener instalada en la misma máquina la suite<br />
ofimática, se podría ampliar la funcionalidad <strong>de</strong> OpenSheet para que por configuración se<br />
pueda elegir el modo <strong>de</strong> conectarse a OpenOffice.org, ya sea a través <strong>de</strong> una tubería o pipe<br />
para una conexión local, o a través <strong>de</strong> un socket por conexión remota.<br />
Esta ampliación en la funcionalidad es sencilla <strong>de</strong> implementar pues sólo es necesario<br />
modificar la clase Bootstrap, que se incluye en la API, para que lea <strong>de</strong> algun fichero <strong>de</strong><br />
configuración la opción elegida y ya establezca el mecanismo <strong>de</strong> comunicación elegido con<br />
OpenOffice.org.<br />
6.2.2. Soporte para fórmulas<br />
A través <strong>de</strong> OpenSheet se permite insertar y extraer datos <strong>de</strong> celdas, concretamente se<br />
permite trabajar con datos numéricos y con ca<strong>de</strong>nas <strong>de</strong> texto; pero OpenOffice.org ofrece<br />
otras posibilida<strong>de</strong>s como trabajar con fórmulas.<br />
Se podría incluir en la API <strong>de</strong> OpenSheet las operaciones para trabajar con fórmulas, y<br />
luego incorporar los mecanismos necesarios para usarlos en el comando y el servicio web.<br />
<strong>La</strong>s operaciones que se podrían implementar son:<br />
Inserción <strong>de</strong> fórmula: permite insertar una fórmula a una celda o rango <strong>de</strong> celdas.<br />
Extracción <strong>de</strong> fórmula: permite recuperar <strong>de</strong> una celda una fórmula asignada. A<strong>de</strong>más,
108 6. CONCLUSIONES<br />
también permitir la recuperación <strong>de</strong> todas las fórmulas <strong>de</strong> un rango.<br />
Validación <strong>de</strong> fórmula: permite realizar la comprobación <strong>de</strong> si una fórmula es correcta<br />
sintácticamente.<br />
Esta ampliación <strong>de</strong> funcionalidad tiene un alcance mayor que la propuesta anterior pues es<br />
necesario realizar cambios en el objeto SpreadSheet y en su interfaz ISpreadSheet. A<strong>de</strong>más<br />
si se quiere usar <strong>de</strong>s<strong>de</strong> el comando y el servicio web es necesario incluir cambios en el script<br />
creado, <strong>de</strong> manera que se puedan incluir las fórmulas en el fichero <strong>de</strong> datos para permitir su<br />
uso.<br />
6.2.3. Añadir nuevos tipos para la inserción <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias<br />
El objeto ScriptExecuter, usado tanto en el comando como en servicio web, es capaz <strong>de</strong><br />
interpretar algunas variables especiales <strong>de</strong>finidas en un objeto Properties para crear objetos e<br />
inyectarlos a un script. Actualmente los tipos <strong>de</strong> variables especiales que se soportan son:<br />
@number;: se transforma en un objeto <strong>de</strong> tipo Double.<br />
@list;: genera una lista <strong>de</strong> ca<strong>de</strong>nas con los valores que le acompañan.<br />
@OpenSheetManager;: inyecta el objeto OpenSheetManager para que sea utilizado<br />
por el script.<br />
@OpenSheetDocument;: permite crear o abrir un documento creando un objeto OpenSheetDocument<br />
que es inyectado a la variable correspondiente <strong>de</strong>l script.<br />
Aunque se pue<strong>de</strong> <strong>de</strong>legar a los scripts que a partir <strong>de</strong> la ca<strong>de</strong>na <strong>de</strong> texto recuperada la<br />
interpreten y generen los objetos que necesiten, sería bueno ampliar los tipos <strong>de</strong> variables<br />
especiales que se soportan, algunos tipos que podrían ser útiles:<br />
Lista heterogénea: <strong>de</strong>finir una lista que sea capaz <strong>de</strong> contener a su vez otras variables<br />
especiales <strong>de</strong> manera que se puedan crear listas heterogéneas. Por ejemplo una lista<br />
que contenga objetos <strong>de</strong> tipo ca<strong>de</strong>na y <strong>de</strong> tipo numérico.<br />
Mapa básico: permitir crear mapas <strong>de</strong> clave/valor don<strong>de</strong> ambos sean tratados como<br />
ca<strong>de</strong>nas.<br />
Mapa heterogéneo: permitir crear mapas don<strong>de</strong> la clave sea una ca<strong>de</strong>na y el valor<br />
pueda ser cualquier tipo <strong>de</strong> las variables especiales.<br />
El implementar estos mecanismos no es complejo, la dificultad viene dada por la necesidad<br />
<strong>de</strong> diseñar una sintaxis sencilla, que permita escribir como el valor <strong>de</strong> una propiedad todo lo
6. CONCLUSIONES 109<br />
necesario para crear objetos <strong>de</strong> esos tipos. <strong>La</strong> sintaxis sencilla es imprescindible puesto que<br />
estos tipos serán usados en los ficheros <strong>de</strong> datos o lista <strong>de</strong> variables que en la mayoría <strong>de</strong> los<br />
casos serán escritos por usuarios.<br />
6.2.4. Crear nuevos scripts para uso general<br />
<strong>La</strong> característica más <strong>de</strong>stacada <strong>de</strong> las aplicaciones generadas, tanto el comando como<br />
el servicio web, son las posibilida<strong>de</strong>s que permiten gracias a la capacidad <strong>de</strong> ejecución <strong>de</strong><br />
scripts <strong>de</strong> Groovy y la capacidad <strong>de</strong> inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias. Como muestra <strong>de</strong> esto se ha<br />
creado un script para uso genérico que en función <strong>de</strong> los datos recibidos realiza una serie <strong>de</strong><br />
operaciones sobre hojas <strong>de</strong> cálculo, pero las posibles funciones <strong>de</strong> estos artefactos software<br />
van más allá, simplemente creando nuevos scripts en lenguaje Groovy.<br />
Algunas i<strong>de</strong>as que pue<strong>de</strong>n contener los scripts son:<br />
Envío <strong>de</strong> correo electrónicos: se pue<strong>de</strong> añadir en los scripts por ejemplo para programar<br />
una tarea que compruebe el contenido <strong>de</strong> <strong>de</strong>terminadas celdas <strong>de</strong> documentos <strong>de</strong><br />
hojas <strong>de</strong> cálculo y según ciertos valores enviar correos electrónicos con algún aviso.<br />
Por ejemplo, en una empresa don<strong>de</strong> el control <strong>de</strong> gestión o la contabilidad se almacene<br />
en documentos <strong>de</strong> hojas <strong>de</strong> cálculo, se programe una tarea que lance el comando con<br />
dicho script <strong>de</strong> manera que se comprueben las celdas que contienen los valores clave y<br />
que si hay alguna anomalía envíe un correo a los <strong>de</strong>partamentos y personas indicadas.<br />
Consultas a bases <strong>de</strong> datos: se pue<strong>de</strong> añadir en los scripts la posibilidad <strong>de</strong> conectarse<br />
a bases <strong>de</strong> datos para integrar su uso con el <strong>de</strong> las hojas <strong>de</strong> cálculo. Por ejemplo, para<br />
realizar una migración en la que se quieren almacenar todos los datos almacenados en<br />
hojas <strong>de</strong> cálculo a una base <strong>de</strong> datos.<br />
Conectividad por socket: se pue<strong>de</strong> añadir la manera <strong>de</strong> comunicarse con otras operaciones<br />
a través <strong>de</strong> sockets para obtener datos a insertar en documentos y viceversa<br />
para enviar datos leídos.<br />
Ejecución <strong>de</strong> otras aplicaciones: se pue<strong>de</strong> añadir la posibilidad <strong>de</strong> que se indique en<br />
el fichero <strong>de</strong> datos la ruta <strong>de</strong> las aplicaciones a ejecutar, <strong>de</strong> manera que haciendo uso<br />
<strong>de</strong> los objetos <strong>de</strong> OpenSheet se extraigan datos <strong>de</strong> documentos <strong>de</strong> hojas <strong>de</strong> cálculo y<br />
se usen como argumentos en la ejecución.<br />
6.2.5. Permitir <strong>de</strong>pen<strong>de</strong>ncias entre scripts<br />
Actualmente el ScriptExecuter tiene la limitación <strong>de</strong> que no permite que el script a ejecutar<br />
tenga <strong>de</strong>pen<strong>de</strong>ncias <strong>de</strong> otros scripts, <strong>de</strong> manera que si existen funciones en otros scripts <strong>de</strong><br />
Groovy estos no se resuelven correctamente y falla.
110 6. CONCLUSIONES<br />
El resolver esta limitación permitiría reutilizar con OpenSheet aquellos scripts escritos en<br />
Groovy para otros propósitos que estuvieran divididos en diferentes ficheros.<br />
6.3. Conclusiones personales<br />
A continuación se exponen las conclusiones personales <strong>de</strong>l autor sobre las experiencias<br />
que se han tenido durante el <strong>de</strong>sarrollo <strong>de</strong>l proyecto.<br />
6.3.1. Conclusiones sobre la metodología <strong>de</strong> planificación<br />
<strong>La</strong>s conclusiones personales sobre el uso <strong>de</strong> la adaptación <strong>de</strong> la metodología ágil Scrum y<br />
<strong>de</strong> las características <strong>de</strong>l entorno <strong>de</strong> este proyecto son las siguientes:<br />
1. Utilizar <strong>de</strong>sarrolladores para llevar a cabo un proyecto o las partes principales sin que<br />
tengan una <strong>de</strong>dicación completa aumenta la dificultad tanto <strong>de</strong> gestión como <strong>de</strong> planificación.<br />
2. <strong>La</strong> metodología <strong>de</strong> planificación usada permite <strong>de</strong>tectar enseguida las <strong>de</strong>sviaciones <strong>de</strong><br />
las planificaciones y actuar en consecuencia.<br />
3. El cambiar los requisitos durante el <strong>de</strong>sarrollo <strong>de</strong>l proyecto se ha realizado <strong>de</strong> manera<br />
sencilla, permitiendo adaptar rápidamente la planificación a las nuevas necesida<strong>de</strong>s.<br />
Creo que a día <strong>de</strong> hoy ofrece más posibilida<strong>de</strong>s la rápida adaptación <strong>de</strong> los requisitos,<br />
que el tratar <strong>de</strong> prever todas las posibles necesida<strong>de</strong>s cuando no se tiene todo el conocimiento<br />
<strong>de</strong> la solución, pues normalmente durante el <strong>de</strong>sarrollo se adquieren nuevos<br />
conocimientos que permiten a su vez <strong>de</strong>tectar nuevos requisitos.<br />
6.3.2. Conclusiones sobre la metodología <strong>de</strong> <strong>de</strong>sarrollo<br />
<strong>La</strong>s conclusiones personales sobre el uso <strong>de</strong> TDD como metodología <strong>de</strong> <strong>de</strong>sarrollo han<br />
sido las siguientes:<br />
1. El uso <strong>de</strong> TDD es complejo para <strong>de</strong>sarrollares que estén acostumbrados a implementar<br />
primero la solución y a realizar las pruebas <strong>de</strong>spués, lo que aumenta en algunos casos<br />
el tiempo <strong>de</strong> <strong>de</strong>sarrollo.<br />
2. El realizar el diseño a partir <strong>de</strong> las pruebas garantiza que todo el código va a estar<br />
probado. De esta manera se evita que una vez realizado el código haya que modificarlo<br />
para po<strong>de</strong>r probarlo. Esto suce<strong>de</strong> cuando es necesario realizar cambios en la visibilidad<br />
<strong>de</strong> métodos o es necesario añadir nuevos métodos para po<strong>de</strong>r inyectar mocks para po<strong>de</strong>r<br />
realizar pruebas unitarias.
6. CONCLUSIONES 111<br />
3. Todos los tipos <strong>de</strong> pruebas son importantes, y aunque se cumplan todas las pruebas unitarias<br />
siempre pue<strong>de</strong>n aparecer problemas ocultos a través <strong>de</strong> la realización <strong>de</strong> pruebas<br />
<strong>de</strong> integración o <strong>de</strong> sistema.<br />
4. <strong>La</strong> refactorización que <strong>de</strong>fine el algoritmo <strong>de</strong> TDD permite eliminar el código repetido,<br />
y por tanto innecesario, en cuanto se crea, obligando a tener código más limpio y<br />
mantenible. Esta refactorización se aplica tanto en el código <strong>de</strong> la aplicación como en<br />
las pruebas, don<strong>de</strong> habitualmente se un uso ina<strong>de</strong>cuado <strong>de</strong>l copiar y pegar.<br />
5. Es imprescindible tener conocimientos <strong>de</strong> patrones <strong>de</strong> diseño y tener un buen criterio<br />
para estructurar aplicaciones cuando se realiza el paso <strong>de</strong> refactorización. Pues es la<br />
manera <strong>de</strong> po<strong>de</strong>r obtener buenos diseños como resultados <strong>de</strong> aplicar este paso <strong>de</strong>l<br />
algoritmo <strong>de</strong> TDD.<br />
6. <strong>La</strong> refactorización no es un paso automático pues necesita que se apliquen los criterios<br />
necesarios para que <strong>de</strong> ella <strong>de</strong> como resultado un buen diseño, pero si es un paso<br />
fundamental.
ANEXOS
Anexo A<br />
Manual <strong>de</strong> usuario<br />
A.1.<br />
OpenSheet Command<br />
OpenSheet Command es una herramienta escrita en Java que permite operar con documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong> manera automática a partir <strong>de</strong> los datos contenidos en un<br />
fichero .properties pasado en la ejecución y <strong>de</strong> un script <strong>de</strong> acciones seleccionado. Esta herramienta<br />
esta diseñada para ser ejecutada <strong>de</strong>s<strong>de</strong> un terminal o consola <strong>de</strong>l sistema, y hace<br />
uso <strong>de</strong> OpenSheet API y OpenOffice.org Calc.<br />
OpenSheet Commnad, a través <strong>de</strong>l script que proporciona, permite realizar las siguientes<br />
operaciones según los valores asignados en el fichero <strong>de</strong> datos a usar en la ejecución:<br />
Inserción y extracción <strong>de</strong> datos <strong>de</strong> celdas.<br />
Añadir y eliminar hojas <strong>de</strong> cálculo a un documento.<br />
Conversión <strong>de</strong> un documento a cualquiera <strong>de</strong> los formatos <strong>de</strong> hojas <strong>de</strong> cálculo soportados<br />
(xls, xlt, xlsx, ods, odt).<br />
Exportar un documento <strong>de</strong> hojas <strong>de</strong> cálculo a PDF.<br />
A.1.1. Instalación<br />
<strong>La</strong> instalación <strong>de</strong> OpenSheet Command es muy simple pues basta con <strong>de</strong>scomprimir el<br />
fichero distribuido en el directorio <strong>de</strong>seado. De esa manera se tendrá el propio comando<br />
OpenSheetCommand.jar y otros directorios que necesita el comando, por tanto para garantizar<br />
su correcto funcionamiento es necesario mantener la estructura que genera el fichero tras<br />
su <strong>de</strong>scompresión.<br />
Para po<strong>de</strong>r usar el comando es necesario tener instalados los siguientes requisitos:<br />
Sistema operativo Windows o GNU/Linux<br />
Java JRE 6<br />
OpenOffice.org 3.0 o superior.<br />
115
116 A. MANUAL DE USUARIO<br />
A.1.2. Operación<br />
Para ejecutar el comando se <strong>de</strong>be escribir en un terminal o consola <strong>de</strong>l sistema lo siguiente:<br />
java -jar OpenSheetCommand.jar -script={script_file} -data={data_file}<br />
Listado A.1: Ejecución OpenSheet Command<br />
En lo indicado en el listado A.1 se <strong>de</strong>ben sustituir los valores entre llaves por los ficheros<br />
que correspondan. <strong>La</strong> <strong>de</strong>scripción <strong>de</strong> los argumentos es la siguiente:<br />
-script= : Es el argumento utilizado para indicar el script a ejecutar, en lugar <strong>de</strong> {script_file}<br />
se <strong>de</strong>be poner la ruta al script que se <strong>de</strong>sea ejecutar. Este argumento es obligatorio.<br />
-data= : Es el argumento utilizado para indicar el fichero <strong>de</strong> datos .properties que contienen<br />
nombres <strong>de</strong> las variables y los valores a inyectar en el script seleccionado. En lugar<br />
<strong>de</strong> {data_file} se <strong>de</strong>be poner la ruta al fichero .properties que se <strong>de</strong>sea utilizar. Este<br />
argumento es obligatorio.<br />
A continuación, se <strong>de</strong>scribirá el formato genérico <strong>de</strong> los ficheros <strong>de</strong> datos.<br />
A.1.3.<br />
Formato <strong>de</strong> fichero <strong>de</strong> datos<br />
El fichero <strong>de</strong> datos es un fichero .properties <strong>de</strong> Java, es <strong>de</strong>cir, es un fichero con pares<br />
clave/valor sensibles a mayúsculas, don<strong>de</strong> la clave es el i<strong>de</strong>ntificador <strong>de</strong> la variable a la que<br />
se le va a inyectar el valor.<br />
El comando por cada clave <strong>de</strong>finida, asigna una ca<strong>de</strong>na con el valor a la variable <strong>de</strong>l script<br />
que tiene como nombre el mismo que el <strong>de</strong> la clave.<br />
Existen unos valores reservados para asignar a las claves, <strong>de</strong> manera que a la variable <strong>de</strong>l<br />
script en lugar <strong>de</strong> asignarle una ca<strong>de</strong>na con el valor, se le inyecta un objeto. Todo valor reservado<br />
tiene la siguiente sintaxis: @palabra_reservada; seguido <strong>de</strong> los valores necesarios<br />
según la variable especial a utilizar.<br />
<strong>La</strong>s variables especiales para inyectar objetos son:<br />
@OpenSheetManager; : Permite inyectar el objeto OpenSheetManager para po<strong>de</strong>r crear y<br />
abrir documentos <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong>s<strong>de</strong> el script. Un ejemplo <strong>de</strong> uso es:<br />
manager = @OpenSheetManager;<br />
Listado A.2: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetManager;
A. MANUAL DE USUARIO 117<br />
Con el listado A.2 se inyectará el objeto OpenSheetManager a la variable manager <strong>de</strong>l<br />
script que se va a ejecutar.<br />
@OpenSheetDocument;create,ruta_fichero : Crea un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo<br />
en la ruta indicada, representado por un objeto IOpenSheetDocument que será inyectado<br />
a la variable <strong>de</strong>l script indicada. Un ejemplo <strong>de</strong> uso es:<br />
documento1 = @OpenSheetDocument;create,contabilidad1.ods<br />
Listado A.3: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetDocument; para crear un<br />
documento<br />
Con el listado A.3 se creará un documento en la ruta <strong>de</strong> ejecución <strong>de</strong> tipo ods con el<br />
nombre indicado y a<strong>de</strong>más se inyectará el objeto OpenSheetDocument, que permite<br />
trabajar con dicho documento, a la variable documento1 <strong>de</strong>l script que se va a ejecutar.<br />
@OpenSheetDocument;open,ruta_fichero : Abre un documento <strong>de</strong> hojas <strong>de</strong> cálculo que<br />
se encuentra en la ruta indicada, representado por un objeto IOpenSheetDocument que<br />
será inyectado a la variable <strong>de</strong>l script indicada. Un ejemplo <strong>de</strong> uso es:<br />
documento1 = @OpenSheetDocument;open,movimientos.xls<br />
Listado A.4: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @OpenSheetDocument; para abrir un<br />
documento<br />
Con el listado A.4 se abrirá el documento movimientos.xls almancenado en la ruta<br />
<strong>de</strong> ejecución y <strong>de</strong> tipo xls y a<strong>de</strong>más se inyectará el objeto OpenSheetDocument, que<br />
permite trabajar con dicho documento, a la variable documento1 <strong>de</strong>l script que se va a<br />
ejecutar.<br />
@number;numero : Permite crear objetos <strong>de</strong> tipo Double. Algunos ejemplos <strong>de</strong> uso son:<br />
interes = @number;2.5<br />
Listado A.5: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @number;<br />
Con el listado A.5 se creará un objeto <strong>de</strong> tipo Double con el valor <strong>de</strong> 2.5 que será<br />
inyectado en la variable interes <strong>de</strong>l script que se va a ejecutar.<br />
@list;valor1,valor2 : Permite crear un objeto List, concretamente una lista <strong>de</strong> ca<strong>de</strong>nas, don<strong>de</strong><br />
cada valor va separado por una coma. Hay que tener en cuenta las siguientes características:<br />
1. Todos los espacios entre los separadores <strong>de</strong> valores son añadidos a la ca<strong>de</strong>na.
118 A. MANUAL DE USUARIO<br />
2. Para insertar un elemento con la ca<strong>de</strong>na vacía basta con poner el separador sin<br />
ningún contenido <strong>de</strong>ntro.<br />
3. Para usar la coma como valor <strong>de</strong>ntro <strong>de</strong>l elemento ca<strong>de</strong>na a añadir en la lista, se<br />
<strong>de</strong>be escapar usando //,<br />
Algunos ejemplos <strong>de</strong> uso:<br />
laborables = @list;lunes,martes,miercoles,jueves,viernes<br />
Listado A.6: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list;<br />
Con el listado A.6 se creará un objeto <strong>de</strong> tipo List con cinco objetos String (“lunes”,<br />
“martes”, “miércoles”, “jueves”, “viernes”) que será inyectado en la variable laborables<br />
<strong>de</strong>l script que se va a ejecutar.<br />
vacaciones = @list;1//,2//,3 y 4 <strong>de</strong> enero,15//,16 y 17 <strong>de</strong> agosto<br />
Listado A.7: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list; con escape <strong>de</strong>l separador<br />
Con el listado A.7 se inyectará un objeto List con dos objetos String (“1,2,3 y 4 <strong>de</strong><br />
enero”, “15,16 y 17 <strong>de</strong> agosto”) a la variable vacaciones <strong>de</strong>l script que se va a ejecutar.<br />
var1 = @list;,ok,,ok<br />
Listado A.8: Ejemplo <strong>de</strong> uso <strong>de</strong> variable especial @list; con ca<strong>de</strong>nas vacias<br />
Con el listado A.8 se inyectará un objeto List con cuatro objetos String (“”, “ok”, “”,<br />
“ok”) a la variable var1 <strong>de</strong>l script que se va a ejecutar.<br />
A.1.4. Uso <strong>de</strong>l script OpenSheetScript.groovy<br />
Con la aplicación OpenSheet Command se distribuye un script, OpenSheetScript.groovy,<br />
preparado para realizar las principales operaciones con documentos <strong>de</strong> hojas <strong>de</strong> cálculo, que<br />
permite la API <strong>de</strong> OpenSheet, a través <strong>de</strong> la asignación <strong>de</strong> valores a una variables <strong>de</strong>finidas<br />
por dicho script. <strong>La</strong>s operaciones que permite realizar el script son:<br />
Inserción y extracción <strong>de</strong> datos <strong>de</strong> celdas.<br />
Añadir y eliminar hojas <strong>de</strong> cálculo a un documento.<br />
Conversión <strong>de</strong> un documento a cualquiera <strong>de</strong> los formatos <strong>de</strong> hojas <strong>de</strong> cálculo soportados<br />
(xls, xlt, xlsx, ods, odt).
A. MANUAL DE USUARIO 119<br />
Exportar un documento <strong>de</strong> hojas <strong>de</strong> cálculo a PDF.<br />
Para indicar al script que operaciones se <strong>de</strong>sean realizar, es necesario hacerlo a través <strong>de</strong>l<br />
fichero <strong>de</strong> datos .properties. Para ello es necesario que el fichero contenga todas las claves<br />
<strong>de</strong>finidas por el script, aunque a algunas no se les asigne ningún valor. <strong>La</strong>s claves o variables<br />
<strong>de</strong>finidas por el script son las siguientes:<br />
1. openSheetDocument: Es la variable que contiene el objeto OpenSheetDocument con<br />
el que <strong>de</strong>be trabajar. Siempre <strong>de</strong>be llevar valor, y <strong>de</strong>be ser la variable especial <strong>de</strong> comando<br />
@OpenSheetDocument; con los parámetros <strong>de</strong>seados.<br />
2. logFileName: Es la variable don<strong>de</strong> se le pue<strong>de</strong> especificar la ruta y el nombre <strong>de</strong>l fichero<br />
<strong>de</strong> log. Si no se le asigna valor, por <strong>de</strong>fecto crea un fichero en la ruta <strong>de</strong> ejecución<br />
con el nombre <strong>opensheet</strong>.log.<br />
3. <strong>de</strong>leteSheets: Es la variable don<strong>de</strong> se le indica el nombre <strong>de</strong> las hojas <strong>de</strong> cálculo que<br />
se quieren borrar en el documento. Si no se asigna valor no realizará la operación <strong>de</strong><br />
borrado por nombre.<br />
4. <strong>de</strong>leteSheetsByPosition: Es la variable don<strong>de</strong> se le especifica la posición <strong>de</strong> las hojas<br />
<strong>de</strong> cálculo que se quieren borrar en el documento. Si no se asigna valor no realizará la<br />
operación <strong>de</strong> borrado por posición.<br />
5. addSheets: Es la variable don<strong>de</strong> se le asigna el nombre <strong>de</strong> las hojas <strong>de</strong> cálculo que se<br />
quieren añadir al documento. Si no se asigna valor no realizará la operación <strong>de</strong> añadir<br />
hojas <strong>de</strong> cálculo.<br />
6. insertCellsValues: Es la variable don<strong>de</strong> se asigna cada uno <strong>de</strong> los valores a insertar en<br />
celdas como texto, usando el nombre <strong>de</strong> las hojas <strong>de</strong> cálculo para referenciarlas. Si no<br />
se asigna valor a la variable no realizará la operación que representa.<br />
7. insertCellsValuesBySheetPosition: Es la variable don<strong>de</strong> se asigna cada uno <strong>de</strong> los<br />
valores a insertar en celdas como texto, usando la posición <strong>de</strong> las hojas <strong>de</strong> cálculo<br />
para referenciarlas. Si no se asigna valor a la variable no realizará la operación que<br />
representa.<br />
8. insertCellsNumericValues: Es la variable don<strong>de</strong> se le asigna cada uno <strong>de</strong> los valores<br />
a insertar en celdas como valores numéricos, usando el nombre <strong>de</strong> las hojas <strong>de</strong> cálculo<br />
para referenciarlas. Si no se asigna valor a la variable no realizará la operación que<br />
representa.<br />
9. insertCellsNumericValuesBySheetPosition: Es la variable don<strong>de</strong> se le asigna cada<br />
uno <strong>de</strong> los valores a insertar en celdas como valores numéricos, usando la posición <strong>de</strong>
120 A. MANUAL DE USUARIO<br />
las hojas <strong>de</strong> cálculo para referenciarlas. Si no se asigna valor a la variable no realizará<br />
la operación que representa.<br />
10. extractCellsValues: Es la variable don<strong>de</strong> se le especifica las celdas que <strong>de</strong> las que se<br />
quiere extraer su valor a un fichero, usando el nombre <strong>de</strong> las hojas <strong>de</strong> cálculo para referenciarlas.<br />
Si no se asigna valor a la variable no realizará la operación que representa.<br />
11. extractCellsValuesBySheetPosition: Es la variable don<strong>de</strong> se le especifica las celdas<br />
que <strong>de</strong> las que se quiere extraer su valor a un fichero, usando la posición <strong>de</strong> las hojas <strong>de</strong><br />
cálculo para referenciarlas. Si no se asigna valor a la variable no realizará la operación<br />
que representa.<br />
12. extractCellsValuesFile: Es la variable don<strong>de</strong> se le pue<strong>de</strong> especificar la ruta y el nombre<br />
<strong>de</strong>l fichero don<strong>de</strong> se <strong>de</strong>ben guardar los valores extraídos <strong>de</strong> las celdas. Si no se le<br />
asigna valor, por <strong>de</strong>fecto crea un fichero en la ruta <strong>de</strong> ejecución con el nombre <strong>opensheet</strong>.out.<br />
13. saveDocumentTo: Es la variable don<strong>de</strong> se le pue<strong>de</strong> especificar que guar<strong>de</strong> el documento<br />
modificado con otro nombre y formato. Es <strong>de</strong>cir, se pue<strong>de</strong> usar para realizar<br />
una conversión <strong>de</strong> formato, para ello basta con usar un nombre <strong>de</strong> fichero con la extensión<br />
<strong>de</strong>l formato al que se <strong>de</strong>sea convertir. A<strong>de</strong>más, también permite la exportación<br />
a PDF. Si no se le asigna valor entonces realiza el salvado en el fichero <strong>de</strong> origen<br />
indicado en la variable openSheetDocument.<br />
Hay que tener en cuenta que siempre <strong>de</strong>ben estar <strong>de</strong>finidas todas las variables en el fichero<br />
<strong>de</strong> datos, en el caso <strong>de</strong> que no se quiera realizar alguna acción, basta con no asignarle<br />
valor.<br />
A continuación, se explicará en mayor <strong>de</strong> <strong>de</strong>talle cada una <strong>de</strong> las variables <strong>de</strong>l script.<br />
Variable openSheetDocument<br />
Es la variable don<strong>de</strong> el script espera recibir el objeto <strong>de</strong> tipo OpenSheetDocument con el<br />
que <strong>de</strong>be trabajar; es <strong>de</strong>cir, se le <strong>de</strong>be asignar la variable especial, explicada en el apartado<br />
<strong>de</strong>l formato <strong>de</strong>l fichero <strong>de</strong> datos, @OpenSheetDocument; con los parámetros a<strong>de</strong>cuados<br />
según si se quiere crear un nuevo documento <strong>de</strong> hojas <strong>de</strong> cálculo o abrir uno ya existente.<br />
Es obligatorio que esta variable tenga siempre un valor válido asignado. Unos ejemplos <strong>de</strong><br />
asignación <strong>de</strong> valores a esta variable son:<br />
openSheetDocument = @OpenSheetDocument;create,doc.ods<br />
Listado A.9: Ejemplo <strong>de</strong> asignación <strong>de</strong> nuevo documento a la variable openSheetDocument<br />
<strong>de</strong> OpenSheetScript
A. MANUAL DE USUARIO 121<br />
En el listado A.9 se muestra un ejemplo para asignarle a la variable un nuevo documento<br />
llamado doc.ods para trabajar con OpenSheetScript.<br />
openSheetDocument = @OpenSheetDocument;open,doc.ods<br />
Listado A.10: Ejemplo <strong>de</strong> asignación <strong>de</strong> un documento a la variable openSheetDocument <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.10 se muestra un ejemplo para asignar a la variable un documento <strong>de</strong> hojas<br />
<strong>de</strong> cálculo ya existente llamado doc.ods para trabajar con OpenSheetScript.<br />
Variable logFileName<br />
Es la variable don<strong>de</strong> se le pue<strong>de</strong> indicar al script el nombre y ruta don<strong>de</strong> se <strong>de</strong>sea guardar<br />
el fichero <strong>de</strong> log que genera durante su ejecución. En el caso <strong>de</strong> que no se asigne valor, por<br />
<strong>de</strong>fecto, crea un fichero <strong>de</strong> log en el directorio <strong>de</strong> ejecución con el nombre <strong>opensheet</strong>.log.<br />
Unos ejemplos <strong>de</strong> asignación <strong>de</strong> valores a esta variable son:<br />
logFileName =<br />
Listado A.11: Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable logFileName<br />
En el listado A.11 se muestra un ejemplo para usar el fichero <strong>de</strong> log por <strong>de</strong>fecto, es <strong>de</strong>cir,<br />
que no se ha asignado ningún valor a la variable.<br />
logFileName = prueba.log<br />
Listado A.12: Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable logFileName <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.12 se muestra un ejemplo para asignar a la variable el nombre <strong>de</strong> fichero<br />
prueba.log que <strong>de</strong>be utilizar para crear el log; en ese caso se creará en el mismo directorio<br />
<strong>de</strong> ejecución.<br />
Variable <strong>de</strong>leteSheets<br />
Es la variable don<strong>de</strong> el script espera recibir la información para realizar el borrado <strong>de</strong><br />
hojas <strong>de</strong> cálculo a partir <strong>de</strong> los nombres <strong>de</strong> estas. Si no se asigna ningún valor a esta variable<br />
no se realizará la acción relacionada con ella. El valor a introducir en el caso <strong>de</strong> querer<br />
realizar la acción <strong>de</strong> borrado <strong>de</strong>be ser cada una <strong>de</strong> las hojas <strong>de</strong> cálculo a borrar separadas por<br />
punto y coma. Una cosa a tener en cuenta, es que para permitir borrar todas las hojas <strong>de</strong> un<br />
documento el script siempre realiza antes la operación <strong>de</strong> añadir hojas <strong>de</strong> cálculo, es <strong>de</strong>cir,<br />
si crea un documento <strong>de</strong> hojas <strong>de</strong> cálculo nuevo y se <strong>de</strong>sea borrar las tres hojas por <strong>de</strong>fecto,<br />
se pue<strong>de</strong> hacer añadiendo hojas a través <strong>de</strong> la variable a<strong>de</strong>cuada en el fichero <strong>de</strong> datos. Un<br />
ejemplo <strong>de</strong> asignación <strong>de</strong> valores a esta variable es:
122 A. MANUAL DE USUARIO<br />
<strong>de</strong>leteSheets = hoja1;facturas enero;borrador<br />
Listado A.13: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable <strong>de</strong>leteSheets <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.13 se muestra un ejemplo para asignarle a la variable los nombres para que<br />
borre tres hojas <strong>de</strong> cálculo <strong>de</strong>l documento: hoja1, facturas enero y borrador.<br />
Variable <strong>de</strong>leteSheetsByPosition<br />
Es la variable don<strong>de</strong> el script espera recibir la información para realizar el borrado <strong>de</strong> hojas<br />
<strong>de</strong> cálculo a partir <strong>de</strong> la posición <strong>de</strong> estas. Si no se asigna ningún valor a esta variable no se<br />
realizará la acción relacionada con ella. El valor a introducir en el caso <strong>de</strong> querer realizar la<br />
acción <strong>de</strong> borrado <strong>de</strong>be ser cada una <strong>de</strong> las posiciones <strong>de</strong> hojas <strong>de</strong> cálculo a borrar separadas<br />
por punto y coma. Es importante tener en cuenta tres cosas, la primera es que las posiciones<br />
empiezan con el 0; la segunda es que una vez que se borra una hoja <strong>de</strong> cálculo, todas las<br />
hojas que estaban <strong>de</strong>trás <strong>de</strong> la eliminada reducen su posición en uno; la tercera cosa a tener<br />
en cuenta, es que para permitir borrar todas las hojas <strong>de</strong> un documento el script siempre<br />
realiza antes la operación <strong>de</strong> añadir hojas <strong>de</strong> cálculo. Uns ejemplos <strong>de</strong> asignación <strong>de</strong> valores<br />
a esta variable son:<br />
<strong>de</strong>leteSheets = 2;1;0<br />
Listado A.14: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable <strong>de</strong>leteSheetsByPosition <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.14 se muestra un ejemplo para borrar las hojas <strong>de</strong> las posiciones 2, 1 y<br />
0. Al colocar las variables en el or<strong>de</strong>n inverso, el borrado se pue<strong>de</strong> realizar sin problemas,<br />
puesto que al borrar la 2 no afectará al or<strong>de</strong>n <strong>de</strong> la 1 y <strong>de</strong> la 0, y así suce<strong>de</strong> con la 1.<br />
<strong>de</strong>leteSheets = 0;0;0<br />
Listado A.15: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores repetidos a la variable<br />
<strong>de</strong>leteSheetsByPosition <strong>de</strong> OpenSheetScript<br />
En el listado A.15 se muestra un ejemplo que da el mismo resultado que el ejemplo <strong>de</strong>l<br />
listado A.14, es <strong>de</strong>cir, primero se borrará la primera hoja <strong>de</strong> cálculo, por lo que la segunda<br />
pasará a ser la primera, y la tercera la segunda y así sucesivamente; <strong>de</strong>spués, se borrará la<br />
primera hoja <strong>de</strong> cálculo que en realidad era la segunda en el original, y <strong>de</strong>spués se volverá a<br />
borrar la primera que era la tercera en el or<strong>de</strong>n original.<br />
Variable addSheets<br />
Es la variable don<strong>de</strong> el script espera recibir la información para añadir nuevas hojas <strong>de</strong><br />
cálculo a partir <strong>de</strong> los nombres <strong>de</strong> estas. Si no se asigna ningún valor a esta variable no se
A. MANUAL DE USUARIO 123<br />
realizará la acción relacionada con ella. El valor a introducir en el caso <strong>de</strong> querer realizar<br />
la acción <strong>de</strong> añadir hojas <strong>de</strong> cálculo <strong>de</strong>be ser el nombre <strong>de</strong> cada una <strong>de</strong> las hojas <strong>de</strong> cálculo<br />
a añadir separadas por punto y coma. Una cosa a tener en cuenta es que siempre se realiza<br />
antes la operación <strong>de</strong> añadir hojas <strong>de</strong> cálculo que las <strong>de</strong> borrado, esto permite po<strong>de</strong>r borrar<br />
todas las hojas <strong>de</strong> cálculo existentes o por <strong>de</strong>fecto. Un ejemplo <strong>de</strong> asignación <strong>de</strong> valores a<br />
esta variable es:<br />
addSheets = hoja1;facturas enero;borrador<br />
Listado A.16: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable addSheets <strong>de</strong> OpenSheetScript<br />
En el listado A.16 se muestra un ejemplo para asignarle a la variable los nombres para que<br />
añada tres hojas <strong>de</strong> cálculo al documento: hoja1, facturas enero y borrador.<br />
Variable insertCellsValues<br />
Es la variable don<strong>de</strong> el script espera recibir la información para insertar valores <strong>de</strong> tipo<br />
texto o ca<strong>de</strong>na a celdas <strong>de</strong> las diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por<br />
nombre. Si no se asigna ningún valor a esta variable no se realizará la acción relacionada con<br />
ella. El valor a introducir en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> insertar valores <strong>de</strong> tipo<br />
texto es nombre_hoja_calculo:celda1=valor1,celda2=valor2 y separado por punto y coma<br />
para las diferentes hojas <strong>de</strong> cálculo. Un ejemplo <strong>de</strong> asignación <strong>de</strong> valores a esta variable es:<br />
insertCellsValues = hoja1:c6=Resumen mensual,d5=Del 1 al<br />
20;facturas enero:aa1=Diferencial,a2=11/04/2011;listado:b12=Generado<br />
mensualmente<br />
Listado A.17: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.17 se muestra un ejemplo para asignarle a la variable el valor para que añada<br />
diferentes textos a celdas <strong>de</strong> tres hojas <strong>de</strong> cálculo, concretamente, en la hoja <strong>de</strong> cálculo<br />
llamada hoja1 se insertarán en la celda c6 el texto “Resumen mensual” y en la celda d5 el<br />
texto “Del 1 al 20”; en la hoja facturas enero se insertarán en la celda aa1 el texto “Diferencial”<br />
y en la celda a2 “11/04/2011”; por último, en la celda b12 <strong>de</strong> la hoja listado se insertará<br />
el texto “Generado mensualmente”.<br />
Variable insertCellsValuesBySheetPosition<br />
Es la variable don<strong>de</strong> el script espera recibir la información para insertar valores <strong>de</strong> tipo<br />
texto o ca<strong>de</strong>na a celdas <strong>de</strong> las diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por<br />
posición. Si no se asigna ningún valor a esta variable no se realizará la acción relacionada<br />
con ella. El valor a introducir en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> insertar valores <strong>de</strong><br />
tipo texto es posicion_hoja_calculo:celda1=valor1,celda2=valor2 y separado por punto y<br />
coma para las diferentes hojas <strong>de</strong> cálculo. <strong>La</strong> primera posición se correspon<strong>de</strong> con el 0. Un<br />
ejemplo <strong>de</strong> asignación <strong>de</strong> valores a esta variable es:
124 A. MANUAL DE USUARIO<br />
insertCellsValuesBySheetPosition = 0:c6=Resumen mensual,d5=Del 1 al<br />
20;2:aa1=Diferencial,a2=11/04/2011;1:b12=Generado<br />
mensualmente<br />
Listado A.18: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.18 se muestra un ejemplo para asignarle a la variable el valor para que<br />
añada diferentes textos a celdas <strong>de</strong> tres hojas <strong>de</strong> cálculo, concretamente, en la hoja <strong>de</strong> cálculo<br />
con la primera posición se insertarán en la celda c6 el texto “Resumen mensual” y en la celda<br />
d5 el texto “Del 1 al 20”; en la hoja con la tercera posición se insertarán en la celda aa1 el<br />
texto “Diferencial” y en la celda a2 “11/04/2011”; por último, en la celda b12 <strong>de</strong> la hoja con<br />
segunda posición se insertará el texto “Generado mensualmente”.<br />
Variable insertCellsNumericValues<br />
Es la variable don<strong>de</strong> el script espera recibir la información para insertar valores <strong>de</strong> tipo numérico<br />
a celdas <strong>de</strong> las diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por nombre.<br />
Si no se asigna ningún valor a esta variable no se realizará la acción relacionada con ella. El<br />
valor a introducir en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> insertar valores <strong>de</strong> tipo numérico<br />
es nombre_hoja_calculo:celda1=valor1,celda2=valor2 y separado por punto y coma para<br />
las diferentes hojas <strong>de</strong> cálculo. Un ejemplo <strong>de</strong> asignación <strong>de</strong> valores a esta variable es:<br />
insertCellsNumericValues = hoja1:c6=12.45,d5=1050;facturas<br />
enero:aa1=275589,a2=23;listado:b12=31<br />
Listado A.19: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.19 se muestra un ejemplo para asignarle a la variable el valor para que<br />
añada diferentes valores numéricos a celdas <strong>de</strong> tres hojas <strong>de</strong> cálculo, concretamente, en la<br />
hoja <strong>de</strong> cálculo llamada hoja1 se insertarán en la celda c6 el valor numérico 12.45 y en la<br />
celda d5 1050; en la hoja facturas enero se insertarán en la celda aa1 el valor numérico<br />
275589 y en la celda a2 23; por último, en la celda b12 <strong>de</strong> la hoja listado se insertará el valor<br />
numérico 31.<br />
Variable insertCellsNumericValuesBySheetPosition<br />
Es la variable don<strong>de</strong> el script espera recibir la información para insertar valores <strong>de</strong> tipo numérico<br />
a celdas <strong>de</strong> las diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por posición.<br />
Si no se asigna ningún valor a esta variable no se realizará la acción relacionada con ella. El<br />
valor a introducir en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> insertar valores <strong>de</strong> tipo numérico<br />
es posicion_hoja_calculo:celda1=valor1,celda2=valor2 y separado por punto y coma para<br />
las diferentes hojas <strong>de</strong> cálculo. <strong>La</strong> primera posición se correspon<strong>de</strong> con el 0. Un ejemplo <strong>de</strong><br />
asignación <strong>de</strong> valores a esta variable es:
A. MANUAL DE USUARIO 125<br />
insertCellsNumericValuesBySheetPosition = 0:c6=12.45,d5=1050;2:aa1<br />
=275589,a2=23;1:b12=31<br />
mensualmente<br />
Listado A.20: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable insertCellsValues <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.18 se muestra un ejemplo para asignarle a la variable el valor para que<br />
añada diferentes valores numéricos a celdas <strong>de</strong> tres hojas <strong>de</strong> cálculo, concretamente, en la<br />
hoja <strong>de</strong> cálculo con la primera posición se insertarán en la celda c6 el valor numérico 12.45<br />
y en la celda d5 1050; en la hoja con la tercera posición se insertarán en la celda aa1 el valor<br />
numérico 275589 y en la celda a2 23; por último, en la celda b12 <strong>de</strong> la hoja con segunda<br />
posición se insertará el valor numérico 31.<br />
Variable extractCellsValues<br />
Es la variable don<strong>de</strong> el script espera recibir la información para extraer los <strong>de</strong> celdas <strong>de</strong><br />
las diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por nombre. Si no se asigna<br />
ningún valor a esta variable no se realizará la acción relacionada con ella. El valor a introducir<br />
en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> extracción <strong>de</strong> valores es nombre_hoja_-<br />
calculo:celda1,celda2 y separado por punto y coma para las diferentes hojas <strong>de</strong> cálculo. Los<br />
valores extraídos se guardarán en el fichero que contenga la variable extractCellsValuesFile.<br />
Un ejemplo <strong>de</strong> asignación <strong>de</strong> valores a esta variable es:<br />
extractCellsValues = hoja1:c6,d5;facturas enero:aa1,a2;listado:b12<br />
Listado A.21: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable extractCellsValues <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.21 se muestra un ejemplo para asignarle a la variable el valor para que<br />
extraiga <strong>de</strong> diferentes celdas los valores que contengan, concretamente <strong>de</strong> celdas <strong>de</strong> tres<br />
hojas <strong>de</strong> cálculo: <strong>de</strong> la hoja <strong>de</strong> cálculo llamada hoja1 se extraerán los valores almacenados<br />
en las celdas c6 y d5; <strong>de</strong> la hoja facturas enero se extraerán los valores <strong>de</strong> las celdas aa1 y<br />
a2; por último, se extraerá el valor <strong>de</strong> la celda b12 <strong>de</strong> la hoja listado.<br />
Variable extractCellsValuesBySheetPosition<br />
Es la variable don<strong>de</strong> el script espera recibir la información para extraer los <strong>de</strong> celdas <strong>de</strong> las<br />
diferentes hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciadas por posición. Si no se asigna ningún<br />
valor a esta variable no se realizará la acción relacionada con ella. El valor a introducir<br />
en el caso <strong>de</strong> querer realizar la acción <strong>de</strong> extracción <strong>de</strong> valores es posicion_hoja_calculo:celda1,celda2<br />
y separado por punto y coma para las diferentes hojas <strong>de</strong> cálculo; teniendo<br />
en cuenta que la primera posición se correspon<strong>de</strong> con el 0. Los valores extraídos se guardarán<br />
en el fichero que contenga la variable extractCellsValuesFile. Un ejemplo <strong>de</strong> asignación<br />
<strong>de</strong> valores a esta variable es:
126 A. MANUAL DE USUARIO<br />
extractCellsValues = 0:c6,d5;2:aa1,a2;1:b12<br />
Listado A.22: Ejemplo <strong>de</strong> asignación <strong>de</strong> valores a la variable<br />
extractCellsValuesBySheetPosition <strong>de</strong> OpenSheetScript<br />
En el listado A.22 se muestra un ejemplo para asignarle a la variable el valor para que<br />
extraiga <strong>de</strong> diferentes celdas los valores que contengan, concretamente <strong>de</strong> celdas <strong>de</strong> tres<br />
hojas <strong>de</strong> cálculo: <strong>de</strong> la hoja <strong>de</strong> cálculo que se encuentra en la primera posición se extraerán<br />
los valores almacenados en las celdas c6 y d5; <strong>de</strong> la tercera hojas se extraerán los valores <strong>de</strong><br />
las celdas aa1 y a2; por último, se extraerá el valor <strong>de</strong> la celda b12 <strong>de</strong> la segunda hoja.<br />
Variable extractCellsValuesFile<br />
Es la variable don<strong>de</strong> se le pue<strong>de</strong> indicar al script el nombre y ruta don<strong>de</strong> se <strong>de</strong>sea guardar el<br />
fichero con los datos extraídos <strong>de</strong> las celdas. En el caso <strong>de</strong> que no se asigne valor, por <strong>de</strong>fecto,<br />
crea un fichero en el directorio <strong>de</strong> ejecución con el nombre <strong>opensheet</strong>.out. El fichero creado<br />
tiene la estructura <strong>de</strong> un fichero .properties, don<strong>de</strong> como clave escribe el nombre <strong>de</strong> la hoja <strong>de</strong><br />
cálculo y a continuación la celda, ambas separadas por un punto. Un ejemplo sería “hoja1.d2<br />
= 23” don<strong>de</strong> se indica que la celda d2 <strong>de</strong> la hoja 1 tiene un valor <strong>de</strong> 23. Hay que tener en<br />
cuenta que si el nombre <strong>de</strong> la hoja <strong>de</strong> cálculo contiene espacios entonces no se generará un<br />
fichero <strong>de</strong> propieda<strong>de</strong>s válido. Unos ejemplos <strong>de</strong> asignación <strong>de</strong> valores a esta variable son:<br />
extractCellsValuesFile =<br />
Listado A.23: Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable extractCellsValuesFile<br />
En el listado A.23 se muestra un ejemplo para usar el fichero <strong>de</strong> extracción por <strong>de</strong>fecto, es<br />
<strong>de</strong>cir, que no se ha asignado ningún valor a la variable.<br />
extractCellsValuesFile = resultados_doc1<br />
Listado A.24: Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable extractCellsValuesFile <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.24 se muestra un ejemplo para asignar a la variable el nombre <strong>de</strong> fichero<br />
resultados_doc1 que <strong>de</strong>be utilizar para crear el fichero don<strong>de</strong> se almacenarán los datos<br />
extraídos <strong>de</strong> las celdas <strong>de</strong>l documento; en ese caso se creará en el mismo directorio <strong>de</strong> ejecución.<br />
Variable saveDocumentTo<br />
Es la variable don<strong>de</strong> se le pue<strong>de</strong> indicar al script un nuevo nombre y ruta don<strong>de</strong> se <strong>de</strong>sea<br />
guardar el fichero con el que ha estado trabajando el script. Si el nombre <strong>de</strong> fichero indicado<br />
tiene otra extensión se realizará la conversión a ese formato, y si la extensión es PDF se
A. MANUAL DE USUARIO 127<br />
realizará la exportación. En el caso <strong>de</strong> que no se asigne valor, por <strong>de</strong>fecto, realizará la operación<br />
<strong>de</strong> salvado sobre el fichero pasado a través <strong>de</strong> la variable openSheetDocument. Unos<br />
ejemplos <strong>de</strong> asignación <strong>de</strong> valores a esta variable son:<br />
saveDocumentTo =<br />
Listado A.25: Ejemplo <strong>de</strong> uso por <strong>de</strong>fecto <strong>de</strong> la variable saveDocumentTo<br />
En el listado A.25 se muestra un ejemplo para salvar las modificaciones sobre el documento<br />
<strong>de</strong> entrada, es <strong>de</strong>cir, que no se ha asignado ningún valor a la variable.<br />
saveDocumentTo = doc2.xls<br />
Listado A.26: Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero a la variable saveDocumentTo <strong>de</strong><br />
OpenSheetScript<br />
En el listado A.26 se muestra un ejemplo para asignar a la variable el nombre <strong>de</strong> fichero<br />
doc2.xls, que será el fichero en el que se guardarán los cambios realizados en el fichero <strong>de</strong><br />
entrada. Si el fichero <strong>de</strong> entrada usado tiene una extensión distinta al asignado, <strong>de</strong> manera<br />
automática se realizará la conversión al formato <strong>de</strong>l fichero asignado.<br />
saveDocumentTo = resultados.pdf<br />
Listado A.27: Ejemplo <strong>de</strong> asignación <strong>de</strong> un fichero con extensión PDF a la variable<br />
saveDocumentTo <strong>de</strong> OpenSheetScript<br />
En el listado A.27 se muestra un ejemplo para asignar a la variable el nombre <strong>de</strong> fichero<br />
resultados.pdf, <strong>de</strong> manera que el contenido <strong>de</strong>l documento será exportado a un documento<br />
<strong>de</strong> tipo PDF, y en el documento <strong>de</strong> entrada no se guardarán los cambios realizados.<br />
A.1.5. Ejemplo <strong>de</strong> uso <strong>de</strong> OpenSheet Command<br />
En este apartado se va a mostrar un ejemplo para usar OpenSheet Command, haciendo<br />
uso <strong>de</strong>l script con el que se distribuye el comando.<br />
Los supuestos <strong>de</strong>l ejemplo son los siguientes: en una empresa se tiene un documento<br />
<strong>de</strong> Excel que se quiere usar a modo <strong>de</strong> plantilla, es <strong>de</strong>cir, insertar los datos <strong>de</strong> facturas y<br />
guardarlos en otro documento sin modificar el que se usa como plantilla.<br />
<strong>La</strong> plantilla cuenta con una hoja <strong>de</strong> cálculo por cada mes, y otra más llamada totales. Se<br />
quiere insertar los datos relativos a una factura, concretamente hay que insertar los siguientes<br />
datos:
128 A. MANUAL DE USUARIO<br />
En la hoja enero hay que insertar en la fila 2 <strong>de</strong>s<strong>de</strong> la columna A hasta la E, el nombre<br />
<strong>de</strong> la empresa, el NIF, nombre producto, cantidad y precio por unidad.<br />
En la hoja totales hay que insertar el nombre <strong>de</strong> la empresa concretamente en la celda<br />
aa2.<br />
A<strong>de</strong>más se quieren extraer los datos <strong>de</strong> la celda A7 <strong>de</strong> la hoja enero y <strong>de</strong> la celda ab55 <strong>de</strong> la<br />
hoja totales.<br />
Si los datos a insertar son <strong>de</strong> los siguientes:<br />
Nombre empresa : Tapones S.A<br />
NIF : A-762222<br />
Producto : Corchos PAF-QA1<br />
Cantidad : 105000<br />
Precio unidad : 0,015<br />
El fichero <strong>de</strong> datos que hay que generar es el siguiente:<br />
openSheetDocument = @OpenSheetDocument;open,factura_plantilla.xls<br />
logFileName = factura_plantilla.log<br />
<strong>de</strong>leteSheets =<br />
<strong>de</strong>leteSheetsByPosition =<br />
addSheets =<br />
insertCellsValues = enero:a2=Tapones S.A,b2=A-762222,c2=Corchos PAF-QA1;<br />
totales:aa2=Tapones S.A<br />
insertCellsValuesBySheetPosition =<br />
insertCellsNumericValues = enero:d2=105000,e2=0,015<br />
insertCellsNumericValuesBySheetPosition =<br />
extractCellsValues = enero:a7;totales:ab55<br />
extractCellsValuesBySheetPosition =<br />
extractCellsValuesFile = extracto_insercion.txt<br />
saveDocumentTo = factura_enero.xls<br />
Listado A.28: Ejemplo <strong>de</strong> fichero <strong>de</strong> datos<br />
En el fichero <strong>de</strong> datos <strong>de</strong>l listado A.28 se han asignado valores sólo a las acciones que<br />
se <strong>de</strong>sean realizar, por ejemplo no se van a añadir ni borrar hojas <strong>de</strong> cálculo, ni a insertar<br />
o a extraer valores a través <strong>de</strong> la posición <strong>de</strong> hojas <strong>de</strong> cálculo puesto que en este caso sólo<br />
se conoce el nombre. A<strong>de</strong>más <strong>de</strong> realizar las inserciones y extracciones correspondientes,<br />
se va a crear un fichero <strong>de</strong> log con el nombre factura_plantilla.log y otro con los datos<br />
extraídos, llamado extracto_insercion.txt. A<strong>de</strong>más, todas las modificaciones realizadas se<br />
guardarán en un documento <strong>de</strong>l mismo formato llamado factura_enero.xls sin modificar el<br />
fichero original.
A. MANUAL DE USUARIO 129<br />
Por último habría que ejecutar el comando pasandole el fichero <strong>de</strong> datos generado y el<br />
script OpenSheetScript.groovy.<br />
A.2.<br />
OpenSheet Web Service<br />
OpenSheet Web Service es un servicio web escrito en Java usando JAX-WS que permite<br />
operar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo a partir <strong>de</strong> la selección <strong>de</strong> un script <strong>de</strong> Groovy y<br />
una lista <strong>de</strong> variables o pares clave/valor. Este servicio hace uso <strong>de</strong> OpenSheet API y OpenOffice.org<br />
Calc.<br />
OpenSheet Web Service proporciona dos operaciones:<br />
Operación listScripts: Esta operación <strong>de</strong>vuelve una lista <strong>de</strong> objetos ScriptInfo con la<br />
información necesaria para utilizar cada uno <strong>de</strong> los scripts disponibles.<br />
Operación executeScript: Esta operación permite ejecutar un script pasándole una<br />
lista <strong>de</strong> variables y un objeto Document que pue<strong>de</strong> ser vacío; y una vez ejecutado el<br />
script se <strong>de</strong>volverán los objetos Document que indiquen las variables <strong>de</strong> salida configuradas<br />
en la información <strong>de</strong>l script.<br />
A.2.1.<br />
Requisitos<br />
Para po<strong>de</strong>r usar el comando es necesario tener instalados los siguientes requisitos:<br />
Sistema operativo Windows o GNU/Linux<br />
Java JRE 6<br />
OpenOffice.org 3.0 o superior.<br />
Contenedor <strong>de</strong> servlets Java (Tomcat por ejemplo)<br />
A.2.2. Despliegue<br />
OpenSheet Web Service se distribuye en un fichero .war que hay que <strong>de</strong>splegar en el<br />
contenedor <strong>de</strong> servlets que tenga instalado el usuario. Para más información se <strong>de</strong>be consultar<br />
el manual <strong>de</strong>l propio contenedor.<br />
A.2.3.<br />
Fichero web.xml<br />
En el fichero web.xml <strong>de</strong> OpenSheet Web Service se <strong>de</strong>ben configurar dos variables:<br />
OPENSHEET_SCRIPTS_DIRECTORY: es el directorio que escaneará el servicio web<br />
en cada arranque para localizar cada uno <strong>de</strong> los scripts <strong>de</strong> Groovy disponibles. Estos
130 A. MANUAL DE USUARIO<br />
scripts <strong>de</strong>ben tener a<strong>de</strong>más un fichero <strong>de</strong> propieda<strong>de</strong>s con el mismo nombre <strong>de</strong>l script<br />
pero con extensión .properties, don<strong>de</strong> se indiquen las propieda<strong>de</strong>s que necesita el servicio<br />
para construir un ScriptInfo, esto se explicará con más <strong>de</strong>talle más a<strong>de</strong>lante.<br />
OPENSHEET_CACHE_DIRECTORY: es el directorio don<strong>de</strong> se guardarán los directorios<br />
temporales creados para cada llamada a la operación <strong>de</strong> ejecución <strong>de</strong> un script.<br />
Para evitar que dos llamadas al mismo script en el mismo momento pueda provocar<br />
sobreescrituras, el servicio crea un directorio con un nombre único en el momento <strong>de</strong><br />
recibir la llamada y ahí es don<strong>de</strong> le indica al script que <strong>de</strong>be guardar todos los recursos.<br />
Este directorio único lo crea <strong>de</strong>ntro <strong>de</strong>l directorio temporal, y lo elimina cuando<br />
termina la operación <strong>de</strong> ejecución.<br />
A.2.4. Activar scripts<br />
Por motivos <strong>de</strong> seguridad, sólo se pue<strong>de</strong>n usar aquellos scripts <strong>de</strong> Groovy que se encuentren<br />
<strong>de</strong>ntro <strong>de</strong>l directorio configurado en el fichero web.xml, y que a<strong>de</strong>más tengan un fichero<br />
Properties con el mismo nombre que el script, pero con extensión .properties, con las siguientes<br />
propieda<strong>de</strong>s configuradas:<br />
<strong>de</strong>scription: es la propiedad don<strong>de</strong> se <strong>de</strong>be explicar qué hace el script y cómo se usa,<br />
para que los clientes sepan que variables <strong>de</strong>ben pasar al ejecutarlo.<br />
outputVariables: son los nombres <strong>de</strong> variables <strong>de</strong>l script que contienen la ruta <strong>de</strong> los<br />
ficheros que <strong>de</strong>ben ser <strong>de</strong>vueltos tras la ejecución <strong>de</strong>l script, separados por punto y<br />
coma.<br />
temporalDirectoryVariable: es el nombre <strong>de</strong> la variable <strong>de</strong>l script don<strong>de</strong> el servicio<br />
web <strong>de</strong>be indicarle que directorio temporal tiene asignado para que genere <strong>de</strong>ntro <strong>de</strong><br />
él los ficheros que necesite con el fin <strong>de</strong> evitar conflictos entre diferentes llamadas al<br />
script.<br />
Si un script <strong>de</strong> Groovy se encuentra en el directorio <strong>de</strong> scripts pero no existe un fichero con<br />
su nombre y la extensión .properties que contenga la información indicada, entonces no será<br />
consi<strong>de</strong>rado un script válido para usarlo <strong>de</strong>s<strong>de</strong> la operación <strong>de</strong> ejecución <strong>de</strong>l servicio web.<br />
Esto obliga a que se <strong>de</strong>fina siempre como usar el script, evitando así que se copien scripts<br />
directamente en el directorio sin crear el fichero <strong>de</strong> información.<br />
Para aquellas variables que contengan nombres <strong>de</strong> ficheros, puesto que el servicio web<br />
asigna un directorio temporal para cada ejecución, se <strong>de</strong>be utilizar sólo el nombre y no una<br />
ruta.<br />
Cuando el servicio web lee en las propieda<strong>de</strong>s un valor especial con @OpenSheetDocument;<br />
lo preprocesa y le aña<strong>de</strong> al nombre la ruta al directorio temporal.
A. MANUAL DE USUARIO 131<br />
Ejemplo <strong>de</strong> activación <strong>de</strong> script<br />
En este ejemplo se va a configurar el script que se distribuye por <strong>de</strong>fecto con OpenSheet<br />
Command, OpenSheetScript.groovy.<br />
Para usar el script lo primero es copiarlo en el directorio <strong>de</strong> scripts configurado en el<br />
fichero web.xml, en la variable OPENSHEET_SCRIPTS_DIRECTORY. A continuación, se<br />
<strong>de</strong>be crear un fichero OpenSheetScript.properties con los siguientes valores:<br />
<strong>de</strong>scription=OpenSheetScript es el script por <strong>de</strong>fecto que permite realizar<br />
las<br />
operaciones basicas <strong>de</strong> la API. Para saber como se <strong>de</strong>be usar consultar el<br />
manual<br />
<strong>de</strong> usuario.<br />
outputVariables=saveDocumentTo;extractCellsValuesFile<br />
temporalDirectoryVariable=tempDir<br />
Listado A.29: Ejemplo <strong>de</strong> fichero Properties para script <strong>de</strong> servicio web<br />
En el listado A.29 se pue<strong>de</strong> ver que se ha añadido una <strong>de</strong>scripción para explicar qué hace<br />
el script y cómo usarlo, se han indicado que variables contienen los ficheros que se <strong>de</strong>ben<br />
<strong>de</strong>volver como resultados, en este caso la variable <strong>de</strong> salvar el fichero y la que contiene el<br />
nombre <strong>de</strong>l fichero con los datos extraídos. Por último, se indica a que variable <strong>de</strong>be asignar<br />
el servicio web el directorio temporal para que el script lo use.<br />
A.2.5. Clientes <strong>de</strong> OpenSheet Web Service<br />
No se distribuyen clientes con el servicio web, no obstante es sencillo crear clientes para<br />
este servicio a partir <strong>de</strong>l uso <strong>de</strong> JAX-WS. Si se <strong>de</strong>sea ampliar la información se <strong>de</strong>be consultar<br />
el manual <strong>de</strong> <strong>de</strong>sarrollo.
Anexo B<br />
Manual <strong>de</strong> <strong>de</strong>sarrollo<br />
Este manual está orientado tanto para aquellos <strong>de</strong>sarrolladores que quieren hacer uso <strong>de</strong><br />
la API <strong>de</strong> OpenSheet en sus aplicaciones como para los que quieren ampliar la funcionalidad<br />
<strong>de</strong> OpenSheet Command o Web Service a través <strong>de</strong> la creación <strong>de</strong> nuevos scripts.<br />
B.1.<br />
Direcciones <strong>de</strong> interés<br />
B.1.1. Repositorio<br />
El proyecto OpenSheet cuenta con un repositorio don<strong>de</strong> siempre estará el último código<br />
disponible para ser <strong>de</strong>scargado por cualquier persona que así lo <strong>de</strong>see. <strong>La</strong> URL <strong>de</strong>l repositorio<br />
es la siguiente: https://arco.esi.uclm.es/svn/public/prj/<strong>opensheet</strong>/<br />
En el directorio raíz <strong>de</strong>l repositorio <strong>de</strong>l proyecto se encuentran tres directorios:<br />
trunk: Aquí es don<strong>de</strong> se pue<strong>de</strong> encontrar el código principal que será usado para sacar<br />
las versiones a distribuir <strong>de</strong> los diferentes componentes <strong>de</strong>l proyecto. Si se <strong>de</strong>sea tener<br />
el código más actual y que vaya a formar parte <strong>de</strong> la siguiente versión, se pue<strong>de</strong> coger<br />
el código <strong>de</strong>l trunk.<br />
branches: Aquí es don<strong>de</strong> se generan diferentes ramas <strong>de</strong>l proyecto para <strong>de</strong>sarrollar en<br />
paralelo funcionalida<strong>de</strong>s que en principio no se <strong>de</strong>sean incorporar directamente al proyecto,<br />
y <strong>de</strong> hecho pue<strong>de</strong> que no se lleguen a incorporar a ninguna versión <strong>de</strong>l producto.<br />
Si alguno <strong>de</strong> los <strong>de</strong>sarrollos que se alojan en este directorio se van a usar, entonces se<br />
realizará la operación <strong>de</strong> merge con el trunk, y por tanto, siempre se recomienda tomar<br />
el código <strong>de</strong>l trunk, <strong>de</strong>jando el código <strong>de</strong> este directorio a los <strong>de</strong>sarrolladores <strong>de</strong>l<br />
proyecto.<br />
tags: En este directorio por cada versión sacada se realiza una instantánea <strong>de</strong>l repositorio<br />
y se crea un directorio con el nombre <strong>de</strong> la versión. Este es el directorio don<strong>de</strong> se<br />
pue<strong>de</strong>n obtener el código <strong>de</strong> alguna <strong>de</strong> las versiones distribuidas.<br />
Dentro <strong>de</strong>l directorio trunk la distribución <strong>de</strong>l proyecto es la siguiente:<br />
133
134 B. MANUAL DE DESARROLLO<br />
doc: Es el directorio que contiene la documentación <strong>de</strong>l proyecto. En este directorio se<br />
encuentra el documento <strong>de</strong> hojas <strong>de</strong> cálculo usado para la planificación, el anteproyecto<br />
y los ficheros <strong>de</strong> latex que correspon<strong>de</strong>n a la memoria <strong>de</strong>l proyecto, en los que se<br />
incluyen los manuales <strong>de</strong> usuario y <strong>de</strong> <strong>de</strong>sarrollo.<br />
src: Es el directorio don<strong>de</strong> se encuentra el código fuente <strong>de</strong>l proyecto dividido en los<br />
diferentes paquetes Java. Dentro <strong>de</strong>l directorio src/org/<strong>opensheet</strong>/ se encuentra a su vez<br />
un directorio para los componentes <strong>de</strong>l proyecto y para los scripts:<br />
• api: Contiene el código referente a la API <strong>de</strong> OpenSheet.<br />
• command: Contiene el código referente a OpenSheet Command y la clase para<br />
ejecutar scripts que también es compartida por el servicio web.<br />
• webservice: contiene el código <strong>de</strong> OpenSheet Web Service, excepto la clase <strong>de</strong><br />
ejecución <strong>de</strong> scripts que se encuentra en el paquete <strong>de</strong>l comando.<br />
• scripts: contiene los scripts escritos en Groovy que se distribuyen con las versiones<br />
<strong>de</strong>l comando y los scripts que sirven <strong>de</strong> test <strong>de</strong> estos. Actualmente sólo se ha<br />
generado un script: OpenSheetScript.groovy.<br />
test: Contiene el código <strong>de</strong> todos los tests <strong>de</strong>l proyecto, y la estructura es la misma que<br />
la <strong>de</strong>l directorio src, salvo porque no tiene el directorio scripts y en su lugar tiene un<br />
directorio utils para las clases <strong>de</strong> utilida<strong>de</strong>s <strong>de</strong> las pruebas.<br />
B.1.2. Gestión <strong>de</strong> inci<strong>de</strong>ncias y peticiones <strong>de</strong> mejora<br />
El proyecto cuenta con una herramienta <strong>de</strong> seguimiento <strong>de</strong> errores o bugs, y <strong>de</strong> peticiones<br />
<strong>de</strong> mejora para que los usuarios puedan abrir inci<strong>de</strong>ncias <strong>de</strong> los problemas encontrados y<br />
solicitar mejoras. Esta herramienta se encuentra <strong>de</strong>ntro <strong>de</strong> la aplicación Redmine, la URL es<br />
https://arco.esi.uclm.es:3000/projects/<strong>opensheet</strong>.<br />
A<strong>de</strong>más, <strong>de</strong>s<strong>de</strong> la dirección <strong>de</strong> Redmine se pue<strong>de</strong> ver la actividad <strong>de</strong>l proyecto y realizar<br />
comparación entre versiones <strong>de</strong>s<strong>de</strong> la propia web.<br />
B.2.<br />
OpenSheet API<br />
<strong>La</strong> librería o API <strong>de</strong> OpenSheet permite incorporar al <strong>de</strong>sarrollador la funcionalidad necesaria<br />
para trabajar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo en Java <strong>de</strong> una manera sencilla, tanto<br />
en sistemas Windows como GNU/Linux.<br />
OpenSheet API hace uso <strong>de</strong> OpenOffice.org Calc por lo que necesita que esté instalado en<br />
la máquina don<strong>de</strong> se va a usar, es necesario que la versión <strong>de</strong> la suite ofimática OpenOffice.org<br />
sea 3.0 o superior. Al usar OpenOffice.org Calc se garantiza una gran compatibilidad<br />
entre los formatos soportados, un amplio soporte y madurez.
B. MANUAL DE DESARROLLO 135<br />
OpenSheet API es compatible con los formatos xls, xlt, xlsx, ods y odt. Y permite realizar<br />
las siguientes operaciones:<br />
Crear nuevos documentos con cualquiera <strong>de</strong> los formatos soportados.<br />
Abrir documentos ya existentes <strong>de</strong> los formatos soportados.<br />
Insertar datos numéricos o <strong>de</strong> texto a celdas o rango <strong>de</strong> celdas.<br />
Extraer datos numéricos y <strong>de</strong> texto <strong>de</strong> celdas y rangos.<br />
Crear nuevas hojas <strong>de</strong> cálculo en un documento.<br />
Eliminar hojas <strong>de</strong> cálculo <strong>de</strong> un documento.<br />
Realizar conversiones entre documentos <strong>de</strong> diferente formato.<br />
Exportar un documento a PDF.<br />
B.2.1. Ejemplos <strong>de</strong> uso<br />
A continuación se muestran diferentes fragmentos <strong>de</strong> código don<strong>de</strong> se muestra como llevar<br />
a cabo las operaciones comentadas más arriba, con la intención <strong>de</strong> mostrar al <strong>de</strong>sarrollador<br />
la facilidad <strong>de</strong> uso <strong>de</strong> OpenSheet API.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.createDocument("balance.xls");<br />
Listado B.1: Crear un nuevo documento con OpenSheet API<br />
El listado B.1 se realiza la operación <strong>de</strong> creación <strong>de</strong> un nuevo documento, simplemente hay<br />
que crear el OpenSheetManager que se encarga <strong>de</strong> localizar la instalación <strong>de</strong> OpenOffice.org,<br />
arrancar el proceso y conectarse a él <strong>de</strong> manera totalmente transparente y automática; y<br />
<strong>de</strong>spués solicitarle al objeto creado que cree un documento con la ruta y el nombre que se<br />
<strong>de</strong>see. <strong>La</strong> interfaz IOpenSheetDocument es la que nos permite trabajar con los documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
Listado B.2: Abrir un documento con OpenSheet API<br />
El listado B.2 se muestra como abrir un documento <strong>de</strong> hojas <strong>de</strong> cálculo ya existente, don<strong>de</strong><br />
al igual que en el ejemplo anterior basta con crear el objeto OpenSheetManager y usar el método<br />
openDocument con la ruta y el fichero que se quiere abrir, <strong>de</strong> manera que nos <strong>de</strong>vuelve<br />
la interfaz IOpenSheetDocument para trabajar con él.
136 B. MANUAL DE DESARROLLO<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
ISpreadSheet sheet1 = oSheetDoc.getSpreadSheet(0);<br />
ISpreadSheet sheetJunio = oSheetDoc.getSpreadSheet("Junio");<br />
sheet1.setCellValue(new CellPosition(0,0), "Revisado");<br />
sheet1.setCellValue(new CellPosition("a2"), "Proyecto A-T");<br />
sheet1.setCellValue(new CellPosition(2,1), 1500.0);<br />
sheetJunio.setCellValue(new CellPosition("a2"), 23.45);<br />
Listado B.3: Insertar datos a celdas con OpenSheet API<br />
El listado B.3 se muestra como insertar datos en celdas <strong>de</strong> las hojas <strong>de</strong> cálculo <strong>de</strong> un documento,<br />
para ello se realiza la apertura <strong>de</strong> un documento balance.xls y se obtienen las interfaces<br />
ISpreadSheet con la llamada a getSpreadSheet para trabajar con dos hojas <strong>de</strong> cálculo, la<br />
hoja <strong>de</strong> la primera posición y otra con el nombre Junio. En las hojas se insertan los datos <strong>de</strong><br />
texto o numéricos usando el método setCellValue con el objeto que representa la posición <strong>de</strong><br />
la celda. Este objeto CellPosition pue<strong>de</strong> ser creado mediante las posiciones X e Y o mediante<br />
el nombre <strong>de</strong> columna y fila.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
ISpreadSheet sheet1 = oSheetDoc.getSpreadSheet(0);<br />
ISpreadSheet sheetJunio = oSheetDoc.getSpreadSheet("Junio");<br />
sheet1.setRangeValue(new CellPosition(0,0), new CellPosition(0,7), "<br />
Revisado");<br />
sheet1.setRangeValue(new CellPosition("c1"), new CellPosition("d6"), "OK"<br />
);<br />
sheet1.setRangeValue(new CellPosition(1,0), new CellPosition(1,7),<br />
1500.0);<br />
sheetJunio.setCellValue(new CellPosition("aa2"),new CellPosition("aa6"),<br />
23.45);<br />
Listado B.4: Insertar datos a rangos con OpenSheet API<br />
El listado B.4 se muestra como insertar datos en rangos <strong>de</strong> celdas en las hojas <strong>de</strong> cálculo<br />
<strong>de</strong> un documento, para ello se realiza la apertura <strong>de</strong> un documento balance.xls y se obtienen<br />
las interfaces ISpreadSheet con la llamada a getSpreadSheet para trabajar con dos hojas <strong>de</strong><br />
cálculo, la hoja <strong>de</strong> la primera posición y otra con el nombre Junio. En las hojas se insertan los<br />
datos <strong>de</strong> texto o numéricos usando el método setRangeValue con los objetos que representan<br />
las posición <strong>de</strong> las celdas que <strong>de</strong>finen el rango, la superior izquierda y la inferior <strong>de</strong>recha.<br />
Este objeto CellPosition pue<strong>de</strong> ser creado mediante las posiciones X e Y o mediante el<br />
nombre <strong>de</strong> columna y fila. <strong>La</strong> operación setRangeValue inserta el mismo valor a todas las<br />
celdas <strong>de</strong>l rango.
B. MANUAL DE DESARROLLO 137<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
ISpreadSheet sheet = oSheetDoc.getSpreadSheet("Nominas");<br />
double salario = sheet.getCellValue(new CellPosition("d34"));<br />
String empleado = sheet.getCellText(new CellPosition("c34"));<br />
Object celdaAA1 = sheet.getCellContent(new CellPosition("aa1"));<br />
Listado B.5: Extraer datos <strong>de</strong> celdas con OpenSheet API<br />
El listado B.5 se muestra como extraer datos <strong>de</strong> celdas <strong>de</strong> una hoja <strong>de</strong> cálculo <strong>de</strong> un documento,<br />
para ello se realiza la apertura <strong>de</strong> un documento balance.xls y se obtiene la interfaz<br />
ISpreadSheet con la llamada a getSpreadSheet para trabajar con la hoja <strong>de</strong> cálculo con el<br />
nombre Nominas. De la hoja se extraen valores <strong>de</strong> diferentes celdas, usando diferentes métodos:<br />
getCellValue para obtener los valores numéricos, getCellText para extraer las ca<strong>de</strong>nas<br />
<strong>de</strong> texto y getCellContent que extrae lo que contenga la celda sea un valor numérico o texto<br />
y lo <strong>de</strong>vuelve como un Object.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
ISpreadSheet sheet = oSheetDoc.getSpreadSheet("Nominas");<br />
List salarios = sheet.getRangeValues(new CellPosition("d34"), new<br />
CellPosition("d289"));<br />
List empleados = sheet.getRangeTexts(new CellPosition("c34"), new<br />
CellPosition("c289"));<br />
List celdasAA1_AB23 = sheet.getRangeContent(new CellPosition("aa1<br />
"),new<br />
CellPosition("ab23"));<br />
Listado B.6: Extraer datos <strong>de</strong> rangos <strong>de</strong> celdas con OpenSheet API<br />
El listado B.6 se muestra como extraer datos <strong>de</strong> rangos <strong>de</strong> celdas <strong>de</strong> una hoja <strong>de</strong> cálculo<br />
<strong>de</strong> un documento, para ello se realiza la apertura <strong>de</strong> un documento balance.xls y se obtiene<br />
la interfaz ISpreadSheet con la llamada a getSpreadSheet para trabajar con la hoja <strong>de</strong> cálculo<br />
con el nombre Nominas. De la hoja se extraen diferentes listas <strong>de</strong> valores <strong>de</strong> los diferentes<br />
rangos <strong>de</strong> celdas, usando distintos métodos: getRangeValues para obtener la lista con los<br />
valores numéricos, getRangeTexts para extraer una lista con las ca<strong>de</strong>nas <strong>de</strong> texto <strong>de</strong> las celdas<br />
y getRangeContent que extrae lo que contenga cada una <strong>de</strong> las celdas <strong>de</strong>l rango sea un valor<br />
numérico o texto y lo <strong>de</strong>vuelve como una lista <strong>de</strong> Object.<br />
El listado B.7 se muestra como añadir nuevas hojas <strong>de</strong> cálculo a un documento, para<br />
ello se realiza la apertura <strong>de</strong> un documento balance.xls y aña<strong>de</strong>n hojas a través <strong>de</strong>l método
138 B. MANUAL DE DESARROLLO<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
ISpreadSheet sheetNueva =<br />
ISpreadSheet sheetCierre =<br />
oSheetDoc.addSpreadSheet();<br />
oSheetDoc.addSpreadSheet("Cierre");<br />
Listado B.7: Añadir hojas <strong>de</strong> cálculo con OpenSheet API<br />
addSpreadSheet. Si se llama al método sin nombre la crea con uno por <strong>de</strong>fecto, y si se le<br />
pasa un nombre crea una nueva hoja con dicho nombre.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
oSheetDoc.<strong>de</strong>leteSpreadSheet(0);<br />
oSheetDoc.<strong>de</strong>leteSpreadSheet("Balance 2009");<br />
Listado B.8: Borrar hojas <strong>de</strong> cálculo con OpenSheet API<br />
El listado B.8 se muestra como borrar hojas <strong>de</strong> cálculo <strong>de</strong> un documento, para ello se realiza<br />
la apertura <strong>de</strong> un documento balance.xls y borran las hojas <strong>de</strong>seadas a través <strong>de</strong>l método<br />
<strong>de</strong>leteSpreadSheet, bien pasándole la posición <strong>de</strong> la hoja en el documento o el nombre <strong>de</strong> la<br />
hoja.<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
oDoc.saveAs("balance.ods");<br />
Listado B.9: Convertir un documento <strong>de</strong> un formato a otro con OpenSheet API<br />
El listado B.9 se muestra como convertir un documento <strong>de</strong> un formato a otro, para ello<br />
basta con salvar un documento <strong>de</strong> hojas <strong>de</strong> cálculo a través <strong>de</strong>l método saveAs usando la<br />
extensión <strong>de</strong>seada.<br />
El listado B.10 se muestra como exportar un documento <strong>de</strong> un formato a PDF, para ello<br />
basta con llamar al método exportToPDF con la ruta y el nombre <strong>de</strong>l fichero que se <strong>de</strong>see y<br />
con la extensión .pdf.<br />
B.2.2. Clases y métodos principales<br />
En este apartado se explican las clases y métodos principales que permiten al <strong>de</strong>sarrollador<br />
hacerse una i<strong>de</strong>a <strong>de</strong> las herramientas <strong>de</strong> las que dispone, pero para entrar en más <strong>de</strong>talles se<br />
<strong>de</strong>be consultar la documentación en Javadoc <strong>de</strong>l proyecto OpenSheet que se distribuye con<br />
la propia OpenSheet API o bien generarlo a partir <strong>de</strong>l código disponible en el repositorio.
B. MANUAL DE DESARROLLO 139<br />
OpenSheetManager oSheetManager = new OpenSheetManager();<br />
IOpenSheetDocument oDoc = oSheetManager.openDocument("balance.xls");<br />
oDoc.exportToPDF("balance.pdf");<br />
Listado B.10: Exportar un documento a formato PDF con OpenSheet API<br />
OpenSheet API tiene las siguientes clases principales:<br />
OpenSheetManager: Es la clase factoría que permite crear objetos con la interfaz<br />
IOpenSheetDocument, es <strong>de</strong>cir, los objetos que representan los documentos <strong>de</strong> hojas<br />
<strong>de</strong> cálculo. Cuando se crea un objeto <strong>de</strong> esta clase, se realiza una búsqueda <strong>de</strong> la<br />
instalación <strong>de</strong> OpenOffice.org en la máquina para arrancar el servicio y conectarse<br />
a él, todo <strong>de</strong> manera automática y transparente, haciendo uso <strong>de</strong> la clase modificada<br />
Bootstrap <strong>de</strong>l SDK <strong>de</strong> UNO. Esta clase tiene los siguientes métodos:<br />
• createDocument(String documentPath): Crea un documento con el nombre en la<br />
ruta indicada, y <strong>de</strong>vuelve la interfaz IOpenSheetDocument para trabajar con él.<br />
• openDocument(String documentPath): Abre un documento en el path indicado,<br />
y <strong>de</strong>vuelve la interfaz IOpenSheetDocument para trabajar con él.<br />
• terminate(): Es la operación que permite liberar los recursos <strong>de</strong> OpenOffice.org.<br />
Al <strong>de</strong>jar <strong>de</strong> trabajar con los objetos <strong>de</strong> OpenSheet API se <strong>de</strong>be llamar siempre<br />
a este método, por lo tanto se <strong>de</strong>be guardar la instancia <strong>de</strong> OpenSheetManager<br />
hasta que se llame a este método.<br />
IOpenSheetDocument: Es la interfaz que permite trabajar con un documento <strong>de</strong> hojas<br />
<strong>de</strong> cálculo. <strong>La</strong>s operaciones que permite son:<br />
• getSpreadSheetsNames(): Devuelve un array con los nombres <strong>de</strong> todas las hojas<br />
<strong>de</strong> cálculo <strong>de</strong>l documento.<br />
• getSpreadSheet: Mediante la sobrecarga <strong>de</strong> métodos permite recuperar el objeto<br />
ISpreadSheet, que representa una hoja <strong>de</strong> cálculo, bien indicando su posición en<br />
el documento o indicando su nombre.<br />
• addSpreadSheet: Mediante la sobrecarga <strong>de</strong> métodos permite añadir una nueva<br />
hoja <strong>de</strong> cálculo con un nombre por <strong>de</strong>fecto o dándole un nombre específico.<br />
• <strong>de</strong>leteSpreadSheet: Mediante la sobrecarga <strong>de</strong> métodos permite eliminar una hoja<br />
<strong>de</strong> cálculo a través <strong>de</strong> su posición o <strong>de</strong> su nombre.<br />
• save(): Este método permite salvar los cambios realizados en un documento.<br />
• saveAs(String documentPath): Permite tanto salvar el documento actual con otro<br />
nombre, como realizar una conversión <strong>de</strong> formato si se usa otra extensión.
140 B. MANUAL DE DESARROLLO<br />
• exportToPDF(String documenPath): Permite exportar un documento al formato<br />
PDF.<br />
• containsSpreadSheet(String name): Permite comprobar si el documento contiene<br />
una hoja <strong>de</strong> cálculo con el nombre indicado por parámetro.<br />
• close(): Cierra el documento y el fichero asociado. Este método <strong>de</strong>be llamarse<br />
siempre <strong>de</strong>spués <strong>de</strong> trabajar con un documento.<br />
ISpreadSheet: Es la interfaz que permite trabajar con un hoja <strong>de</strong> cálculo <strong>de</strong> un documento<br />
y sus celdas. <strong>La</strong>s operaciones que permite son:<br />
• setCellValue: A través <strong>de</strong> la sobrecarga <strong>de</strong> métodos permite insertar un valor<br />
numérico o un texto a una celda representada por el objeto CellPosition.<br />
• setRangeValue: A través <strong>de</strong> la sobrecarga <strong>de</strong> métodos permite insertar un valor<br />
numérico o un texto a un rango <strong>de</strong> celdas representado por dos objetos CellPosition,<br />
el primero que indica la celda <strong>de</strong> la esquina superior izquierda, y el segundo<br />
que indica la celda <strong>de</strong> la esquina inferior <strong>de</strong>recha.<br />
• getCellValue(CellPosition position): Permite recuperar un double <strong>de</strong> una celda<br />
representada por el objeto CellPosition.<br />
• getCellText(CellPosition position): Permite recuperar un String <strong>de</strong> una celda representada<br />
por el objeto CellPosition.<br />
• getRangeValues(CellPosition firstCellPosition, CellPosition lastCellPosition): Permite<br />
recuperar una lista <strong>de</strong> double <strong>de</strong> un rango <strong>de</strong> celdas representado por dos objetos<br />
CellPosition, el primero que indica la celda <strong>de</strong> la esquina superior izquierda,<br />
y el segundo que indica la celda <strong>de</strong> la esquina inferior <strong>de</strong>recha.<br />
• getRangeTexts(CellPosition firstCellPosition, CellPosition lastCellPosition): Permite<br />
recuperar una lista <strong>de</strong> String <strong>de</strong> un rango <strong>de</strong> celdas representado por dos objetos<br />
CellPosition, el primero que indica la celda <strong>de</strong> la esquina superior izquierda,<br />
y el segundo que indica la celda <strong>de</strong> la esquina inferior <strong>de</strong>recha.<br />
• getCellContent(CellPosition position): Permite recuperar un Object que contiene<br />
el valor <strong>de</strong> una celda, representada por el objeto CellPosition, sea numérico o<br />
texto.<br />
• getRangeContent(CellPosition firstCellPosition, CellPosition lastCellPosition): Permite<br />
recuperar una lista <strong>de</strong> Object que contiene los valores <strong>de</strong> las celdas <strong>de</strong> un<br />
rango representado por dos objetos CellPosition, el primero que indica la celda<br />
<strong>de</strong> la esquina superior izquierda, y el segundo que indica la celda <strong>de</strong> la esquina<br />
inferior <strong>de</strong>recha, in<strong>de</strong>pendientemente <strong>de</strong> que el contenido sea numérico o texto.<br />
• getName(): Devuelve el nombre <strong>de</strong> la hoja <strong>de</strong> cálculo.
B. MANUAL DE DESARROLLO 141<br />
• rename(String spreadSheetNewName): Permite cambiar el nombre <strong>de</strong> la hoja <strong>de</strong><br />
cálculo.<br />
B.3.<br />
OpenSheet Command<br />
OpenSheet Command es una herramienta escrita en Java que permite operar con documentos<br />
<strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong> manera automática a partir <strong>de</strong> los datos contenidos en un<br />
fichero .properties pasado en la ejecución y <strong>de</strong> un script, escrito en Groovy, <strong>de</strong> acciones seleccionado.<br />
Esta herramienta esta diseñada para ser ejecutada <strong>de</strong>s<strong>de</strong> un terminal o consola<br />
<strong>de</strong>l sistema, y hace uso <strong>de</strong> OpenSheet API y OpenOffice.org Calc.<br />
<strong>La</strong> configuración y uso <strong>de</strong>l comando se pue<strong>de</strong> consultar en el manual <strong>de</strong> usuario. En este<br />
manual se explicará como ampliar su funcionalidad a través <strong>de</strong> scripts escritos en Groovy.<br />
B.3.1. Clases y métodos principales<br />
<strong>La</strong>s clases que componen el comando no son necesarias explicarlas para po<strong>de</strong>r ampliar su<br />
funcionalidad, puesto que basta con enten<strong>de</strong>r como funciona la inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias y<br />
crear un script en Groovy. Si se <strong>de</strong>sea conocer como funciona el comando para realizar mejoras<br />
o modificaciones se <strong>de</strong>be consultar la documentación en Javadoc <strong>de</strong>l proyecto OpenSheet<br />
que se distribuye con la propia OpenSheet API o bien generarlo a partir <strong>de</strong>l código disponible<br />
en el repositorio.<br />
B.3.2. Creación <strong>de</strong> nuevos scripts<br />
<strong>La</strong> principal característica <strong>de</strong> OpenSheet Command es la posibilidad <strong>de</strong> ampliar su funcionalidad<br />
a través <strong>de</strong> scripts a los que se les inyecta las ca<strong>de</strong>nas leídas <strong>de</strong> un fichero <strong>de</strong> datos u<br />
objetos si se han usado valores especiales.<br />
El script <strong>de</strong>be i<strong>de</strong>ntificar a que variables se les va a inyectar valores <strong>de</strong>l fichero <strong>de</strong> datos,<br />
y si esperan ca<strong>de</strong>nas o alguno <strong>de</strong> los objetos que se pue<strong>de</strong>n inyectar al usar los valores<br />
reservados.<br />
Todo valor reservado tiene la sintaxis @palabra_reservada; seguido <strong>de</strong> los valores necesarios<br />
según la variable especial a utilizar. Existen los siguientes valores reservados:<br />
@OpenSheetManager;: Permite inyectar el objeto OpenSheetManager para po<strong>de</strong>r<br />
crear y abrir documentos <strong>de</strong> hojas <strong>de</strong> cálculo <strong>de</strong>s<strong>de</strong> el script.<br />
@OpenSheetDocument;create,ruta_fichero: Crea un nuevo documento <strong>de</strong> hojas <strong>de</strong><br />
cálculo en la ruta indicada, representado por un objeto IOpenSheetDocument que será<br />
inyectado a la variable <strong>de</strong>l script indicada.<br />
@OpenSheetDocument;open,ruta_fichero: Abre un documento <strong>de</strong> hojas <strong>de</strong> cálculo
142 B. MANUAL DE DESARROLLO<br />
que se encuentra en la ruta indicada, representado por un objeto IOpenSheetDocument<br />
que será inyectado a la variable <strong>de</strong>l script indicada.<br />
@list;valor1,valor2: Permite crear un objeto List, concretamente una lista <strong>de</strong> ca<strong>de</strong>nas,<br />
don<strong>de</strong> cada valor va separado por una coma.<br />
@number;numero: Permite crear objetos <strong>de</strong> tipo Double.<br />
Utilizando esos valores y luego mediante el análisis <strong>de</strong> las ca<strong>de</strong>nas pasadas se pue<strong>de</strong> conseguir<br />
recibir los elementos necesarios para realizar cualquier acción <strong>de</strong> manera que pueda<br />
cambiar según el fichero <strong>de</strong> datos utilizado.<br />
Es necesario que las variables a las que se les vaya a inyectar un valor estén <strong>de</strong>finidas y<br />
sean usadas pero sin realizar ninguna asignación, porque la asignación sobreescribe el valor<br />
inyectado.<br />
Se recomienda analizar el script que se distribuye por <strong>de</strong>fecto con el comando, OpenSheetScript.groovy<br />
y leerse el manual <strong>de</strong> usuario para enten<strong>de</strong>r como funciona y así tener un<br />
ejemplo <strong>de</strong> uso <strong>de</strong> scripts.<br />
Limitación <strong>de</strong> uso <strong>de</strong> scripts<br />
Existe la limitación <strong>de</strong> que actualmente OpenSheet Command no permite ejecutar scripts<br />
<strong>de</strong> Groovy con <strong>de</strong>pen<strong>de</strong>ncias a otros ficheros.<br />
B.4.<br />
OpenSheet Web Service<br />
OpenSheet Web Service es un servicio web escrito en Java usando JAX-WS que permite<br />
operar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo a partir <strong>de</strong> la selección <strong>de</strong> un script <strong>de</strong> Groovy y<br />
una lista <strong>de</strong> variables o pares clave/valor. Este servicio hace uso <strong>de</strong> OpenSheet API y OpenOffice.org<br />
Calc.<br />
OpenSheet Web Service proporciona dos operaciones:<br />
Operación listScripts: Esta operación <strong>de</strong>vuelve una lista <strong>de</strong> objetos ScriptInfo con la<br />
información necesaria para utilizar cada uno <strong>de</strong> los scripts disponibles.<br />
Operación executeScript: Esta operación permite ejecutar un script pasándole una<br />
lista <strong>de</strong> variables y un objeto Document que pue<strong>de</strong> ser vacío; y una vez ejecutado el<br />
script se <strong>de</strong>volverán los objetos Document que indiquen las variables <strong>de</strong> salida configuradas<br />
en la información <strong>de</strong>l script.<br />
OpenSheet Web Service por tanto permite ejecutar scripts <strong>de</strong> Groovy <strong>de</strong> manera remota<br />
para operar con documentos <strong>de</strong> hojas <strong>de</strong> cálculo, al igual que se hace con el comando pero en<br />
este caso hay teniendo en cuenta la problemática <strong>de</strong> la invocación <strong>de</strong>s<strong>de</strong> fuera <strong>de</strong>l sistema:
B. MANUAL DE DESARROLLO 143<br />
1. Los scripts que se pue<strong>de</strong>n ejecutar son aquellos que se encuentran en el directorio<br />
configurado y que a<strong>de</strong>más tienen un fichero .properties con su mismo nombre, que<br />
contiene las variables con la información necesaria para generar objetos ScriptInfo<br />
necesarios para la operación listScripts, y las variables que necesita el servicio web.<br />
Al impedir que se puedan ejecutar scripts enviados por el usuario y limitarlos a un<br />
directorio don<strong>de</strong> se a<strong>de</strong>más se añada un fichero con la información <strong>de</strong> uso, se evitan<br />
problemas <strong>de</strong> seguridad.<br />
2. Ahora existe el problema <strong>de</strong> que el mismo script pue<strong>de</strong> ser invocado a la vez y que<br />
los documentos que envía el cliente <strong>de</strong>l servicio web <strong>de</strong>ben almacenarse sin sobreescribir<br />
otros y a<strong>de</strong>más que se puedan i<strong>de</strong>ntificar <strong>de</strong>s<strong>de</strong> la lista <strong>de</strong> variables enviada, que<br />
sustituye al fichero <strong>de</strong> datos. Para ello el servicio web en el directorio temporal, crea<br />
un nuevo directorio para cada llamada a la operación <strong>de</strong> ejecución don<strong>de</strong> se almacena<br />
el documento enviado, y que se le asigna al script para que lo use cuando tenga que<br />
guardar ficheros.<br />
3. Antes <strong>de</strong> enviar las variables para ejecutar el script, el servicio web <strong>de</strong>be parsear los<br />
valores <strong>de</strong> la variables especiales @OpenSheetDocument; tanto create como open<br />
para que el nombre <strong>de</strong>l documento incluya el directorio temporal creado por el servicio<br />
web.<br />
4. Se <strong>de</strong>ben i<strong>de</strong>ntificar todos los ficheros <strong>de</strong> salida que el servicio web <strong>de</strong>be enviar al<br />
cliente, y no borrar dichos ficheros. Estos <strong>de</strong>ben almacenarse en el directorio temporal<br />
haciendo uso <strong>de</strong> la valor que el servicio web inyectará a la variable configurada para<br />
ello, <strong>de</strong> esta forma una vez leídos los ficheros <strong>de</strong> salida, el servicio web pue<strong>de</strong> borrar<br />
todo el contenido <strong>de</strong>l directorio temporal.<br />
B.4.1. Clases y métodos principales<br />
<strong>La</strong>s clases que componen el servicio web no son necesarias explicarlas para po<strong>de</strong>r ampliar<br />
su funcionalidad, puesto que basta con enten<strong>de</strong>r como funciona la inyección <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncias<br />
y crear un script en Groovy. Si se <strong>de</strong>sea conocer como funciona el servicio web para<br />
realizar mejoras o modificaciones se <strong>de</strong>be consultar la documentación en Javadoc <strong>de</strong>l proyecto<br />
OpenSheet que se distribuye con la propia OpenSheet API o bien generarlo a partir <strong>de</strong>l<br />
código disponible en el repositorio.<br />
B.4.2. Creación <strong>de</strong> nuevos scripts<br />
<strong>La</strong> principal característica <strong>de</strong> OpenSheet Web Service es que permite la posibilidad <strong>de</strong><br />
ampliar su funcionalidad a través <strong>de</strong> scripts, al igual que OpenSheet Command, a los que se<br />
les inyecta las ca<strong>de</strong>nas leídas <strong>de</strong> una lista <strong>de</strong> variables enviadas como parámetros u objetos<br />
si se han usado valores especiales.
144 B. MANUAL DE DESARROLLO<br />
El script <strong>de</strong>be i<strong>de</strong>ntificar a que variables se les va a inyectar valores <strong>de</strong>l fichero <strong>de</strong> datos,<br />
y si esperan ca<strong>de</strong>nas o alguno <strong>de</strong> los objetos que se pue<strong>de</strong>n inyectar al usar los valores<br />
reservados.<br />
Todo valor reservado tiene la sintaxis @palabra_reservada; seguido <strong>de</strong> los valores necesarios<br />
según la variable especial a utilizar, estos son los mismos que los usados en OpenSheet<br />
Commnad.<br />
Para los scripts creados para usar <strong>de</strong>s<strong>de</strong> el servicio web hay que tener en cuenta que es<br />
necesario tener una variable don<strong>de</strong> se inyecte la ruta <strong>de</strong>l directorio temporal creado para<br />
cada ejecución, y que será don<strong>de</strong> se <strong>de</strong>ben almacenar los ficheros que se generen. A<strong>de</strong>más,<br />
las variables que se ha configurado en la variable outputVariables <strong>de</strong>l fichero .properties<br />
<strong>de</strong>ben contener la ruta a los ficheros que el servicio web <strong>de</strong>be <strong>de</strong>volver al cliente que invocó<br />
la operación, y estos ficheros no <strong>de</strong>ben ser borrados, si no que serán eliminados junto con el<br />
directorio temporal por el servicio web.<br />
Se recomienda analizar el script que se distribuye por <strong>de</strong>fecto con el comando, OpenSheetScript.groovy<br />
y leerse el manual <strong>de</strong> usuario para enten<strong>de</strong>r como funciona y como se<br />
<strong>de</strong>be configurar para usarse <strong>de</strong>s<strong>de</strong> el servicio web.<br />
A continuación se explican los pasos <strong>de</strong> una ejecución <strong>de</strong> un script para que se comprenda<br />
mejor el proceso.<br />
B.4.3. Pasos <strong>de</strong> la operación executeScript<br />
El servicio web cuando tiene recibe una petición a la operación executeScript para ejecutar<br />
un script realiza los siguientes pasos:<br />
1. Se Genera el directorio temporal único para esa llamada.<br />
2. Si se envía un documento con datos, este se guarda en el directorio temporal creado.<br />
3. Se preprocesan las variables <strong>de</strong> la lista enviada, añadiendo al nombre <strong>de</strong>l documento<br />
asignado a las directivas @OpenSheetDocument;create y @OpenSheetDocument;open<br />
la ruta <strong>de</strong>l directorio temporal creado.<br />
4. Se crea la instancia <strong>de</strong> ScriptExecuter, que es el mismo objeto que ejecuta scripts en el<br />
comando, con los valores preprocesados <strong>de</strong>l paso anterior.<br />
5. Se inyecta el valor <strong>de</strong>l directorio temporal a la variable temporalDirectoryVariable<br />
configurada en el fichero .properties <strong>de</strong>l script.<br />
6. Se ejecuta el script.<br />
7. Se leen todos los ficheros a los que apuntan las variables configuradas en el fichero<br />
.properties <strong>de</strong>l script a través <strong>de</strong> la variable outputVariables.
B. MANUAL DE DESARROLLO 145<br />
8. Se borra el directorio temporal.<br />
9. Se envía la respuesta.<br />
Con la ejecución <strong>de</strong> estos pasos se entien<strong>de</strong> mejor la necesidad <strong>de</strong> configurar en el fichero<br />
<strong>de</strong> .properties <strong>de</strong>l script las variables temporalDirectoryVariable y outputVariables.<br />
B.4.4. Cliente <strong>de</strong> ejemplo<br />
En este apartado se muestra un ejemplo muy básico <strong>de</strong> un cliente <strong>de</strong>l servicio web que<br />
hace uso <strong>de</strong>l script OpenSheetScript.groovy usando siempre el mismo valor <strong>de</strong> las variables<br />
al estar escritas directamente en el código.<br />
Para po<strong>de</strong>r configurar OpenSheetScript.groovy para po<strong>de</strong>r ser usado como script <strong>de</strong>l servicio<br />
web es necesario añadir un fichero .properties junto a él <strong>de</strong>ntro <strong>de</strong>l directorio <strong>de</strong> scripts<br />
configurado en el web.xml. El fichero .properties <strong>de</strong>be contener la información <strong>de</strong>l listado<br />
B.11.<br />
<strong>de</strong>scription=OpenSheetScript es el script por <strong>de</strong>fecto que permite realizar<br />
las<br />
operaciones basicas <strong>de</strong> la API. Para saber como se <strong>de</strong>be usar consultar el<br />
manual<br />
<strong>de</strong> usuario.<br />
outputVariables=saveDocumentTo;extractCellsValuesFile<br />
temporalDirectoryVariable=tempDir<br />
Listado B.11: Ejemplo <strong>de</strong> fichero Properties para script <strong>de</strong> servicio web<br />
Al usar el saveDocumentTo como variable <strong>de</strong> salida, si se quiere recuperar ese documento<br />
tras la ejecución se le <strong>de</strong>be asignar un valor en la lista <strong>de</strong> variables en cada llamada.<br />
A continuación, se muestra un ejemplo <strong>de</strong> cliente <strong>de</strong>l servicio web generado automáticamente<br />
a partir <strong>de</strong>l WSDL <strong>de</strong>l servicio usando un plugin que trae Netbeans para trabajar<br />
con aplicaciones web. Concretamente se muestran los métodos añadidos al código generado<br />
automáticamente.<br />
En el listado B.12 se pue<strong>de</strong> en el método main que primero se llama a la operación listScripts()<br />
<strong>de</strong>l servicio web, imprimiendo por pantalla la información recibida. A continuación,<br />
se construye un mapa <strong>de</strong> propieda<strong>de</strong>s que se transformará posteriormente en una lista <strong>de</strong><br />
ScriptVariable; en esas propieda<strong>de</strong>s se meten los valores para realizar las siguientes operaciones:<br />
1. Crear un nuevo documento llamado salida.ods<br />
2. Añadir al documento tres hojas <strong>de</strong> cálculo One_Sheet, tab1 y spread.1
146 B. MANUAL DE DESARROLLO<br />
3. Insertar valores diferentes celdas <strong>de</strong> las hojas <strong>de</strong> cálculo <strong>de</strong>l documento, referenciándolas<br />
tanto por nombre como por posición.<br />
4. Extraer los valores insertados a un fichero.<br />
Después <strong>de</strong> crear las propieda<strong>de</strong>s se llama a la operación executeScript <strong>de</strong>l servicio web,<br />
pasándole un documento vacío, puesto que se va a crear en el servidor, la lista <strong>de</strong> variables<br />
comentada antes y el nombre <strong>de</strong>l primer script encontrado al listarlos, en este caso al configurar<br />
sólo uno sería el OpenSheetScript.groovy. Con los documentos recibidos se ejecuta<br />
una operación que permite salvarlos a disco. En el listado B.13 se pue<strong>de</strong>n ver los métodos auxiliares<br />
empleados para pasar las propieda<strong>de</strong>s a lista <strong>de</strong> variables que necesita la operación,<br />
y para almacenar los objetos Document como ficheros.
B. MANUAL DE DESARROLLO 147<br />
public class Main {<br />
public static void main(String[] args) throws Exception<br />
{<br />
OpenSheetWebServiceService service = new<br />
OpenSheetWebServiceService();<br />
OpenSheetWebService port = service.getOpenSheetWebServicePort();<br />
List listScripts = port.listScripts();<br />
for (ScriptInfo sInfo : listScripts)<br />
{<br />
System.out.println("name:"+sInfo.getName());<br />
System.out.println("<strong>de</strong>scr:"+sInfo.getDescription());<br />
System.out.println("output size:"+sInfo.getOutputVariables().<br />
size());<br />
if (sInfo.getOutputVariables().size() > 0)<br />
System.out.println("output 0:"+sInfo.getOutputVariables()<br />
.get(0));<br />
}<br />
HashMap propertiesData = new HashMap();<br />
propertiesData.put("openSheetDocument", "@OpenSheetDocument;<br />
create,salida.ods");<br />
propertiesData.put("logFileName", "");<br />
propertiesData.put("<strong>de</strong>leteSheets", "");<br />
propertiesData.put("<strong>de</strong>leteSheetsByPosition", "");<br />
propertiesData.put("addSheets", "One_Sheet;tab1;spread.1");<br />
propertiesData.put("insertCellsValues", "tab1:c6=hola mundo!,d5=<br />
hello world!;spread.1:aa1=Welcome,a2=11/04/2011");<br />
propertiesData.put("insertCellsValuesBySheetPosition", "0:a1=<br />
sheet with position 0;1:a2= Bienvenido,c7=OpenSheet;2:cc1=Nat"<br />
);<br />
propertiesData.put("insertCellsNumericValues", "tab1:a11=2.45;<br />
One_Sheet:b2=10.0,c1=345.678");<br />
propertiesData.put("insertCellsNumericValuesBySheetPosition", "0:<br />
a11=11.12;3:b22=23.0,c2=987.6543");<br />
propertiesData.put("extractCellsValues", "tab1:c6,d5,a11;spread<br />
.1:aa1,a2;One_Sheet:b2,c1");<br />
propertiesData.put("extractCellsValuesBySheetPosition", "0:a1,a11<br />
;1:a2,c7;2:cc1;3:b22,c2");<br />
propertiesData.put("extractCellsValuesFile", "");<br />
propertiesData.put("saveDocumentTo", "salida1.ods");<br />
}<br />
}<br />
List documents = port.executeScript(new Document(),<br />
getScriptVariables(propertiesData), listScripts.get(0).getName<br />
());<br />
saveDocuments(documents);<br />
Listado B.12: Ejemplo <strong>de</strong> cliente <strong>de</strong> OpenSheet Web Service - Parte 1
148 B. MANUAL DE DESARROLLO<br />
public static List getScriptVariables(Map variablesMap)<br />
{<br />
List list = new ArrayList();<br />
}<br />
for (String key : variablesMap.keySet())<br />
{<br />
ScriptVariable var = new ScriptVariable();<br />
var.setName(key);<br />
var.setValue(variablesMap.get(key));<br />
list.add(var);<br />
}<br />
return list;<br />
private static void saveDocuments(List documents) throws<br />
IOException<br />
{<br />
for (Document doc : documents)<br />
{<br />
System.out.println("\nSave document ’"+doc.getName()+"’");<br />
saveDocument(doc);<br />
}<br />
}<br />
public static void saveDocument(Document document) throws IOException<br />
{<br />
FileOutputStream fos = null;<br />
try<br />
{<br />
File documentFile = new File(document.getName());<br />
fos = new FileOutputStream(documentFile);<br />
fos.write(document.getContent());<br />
}<br />
finally<br />
{<br />
fos.close();<br />
}<br />
}<br />
Listado B.13: Ejemplo <strong>de</strong> cliente <strong>de</strong> OpenSheet Web Service - Parte 2
Anexo C<br />
GNU Free Documentation License<br />
Version 1.3, 3 November 2008<br />
Copyright c○ 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. <br />
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.<br />
0. PREAMBLE<br />
The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to<br />
assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially.<br />
Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being consi<strong>de</strong>red responsible<br />
for modifications ma<strong>de</strong> by others.<br />
This License is a kind of “copyleft”, which means that <strong>de</strong>rivative works of the document must themselves be free in the same sense. It<br />
complements the GNU General Public License, which is a copyleft license <strong>de</strong>signed for free software.<br />
We have <strong>de</strong>signed this License in or<strong>de</strong>r to use it for manuals for free software, because free software needs free documentation: a<br />
free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software<br />
manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this<br />
License principally for works whose purpose is instruction or reference.<br />
1. APPLICABILITY AND DEFINITIONS<br />
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright hol<strong>de</strong>r saying it can be<br />
distributed un<strong>de</strong>r the terms of this License. Such a notice grants a world-wi<strong>de</strong>, royalty-free license, unlimited in duration, to use that work<br />
un<strong>de</strong>r the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee,<br />
and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission un<strong>de</strong>r copyright<br />
law.<br />
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with<br />
modifications and/or translated into another language.<br />
A “Secondary Section” is a named appendix or a front-matter section of the Document that <strong>de</strong>als exclusively with the relationship of<br />
the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall<br />
directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any<br />
mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial,<br />
philosophical, ethical or political position regarding them.<br />
The “Invariant Sections” are certain Secondary Sections whose titles are <strong>de</strong>signated, as being those of Invariant Sections, in the notice<br />
that says that the Document is released un<strong>de</strong>r this License. If a section does not fit the above <strong>de</strong>finition of Secondary then it is not allowed<br />
to be <strong>de</strong>signated as Invariant. The Document may contain zero Invariant Sections. If the Document does not i<strong>de</strong>ntify any Invariant Sections<br />
then there are none.<br />
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says<br />
that the Document is released un<strong>de</strong>r this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25<br />
words.<br />
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the<br />
general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels)<br />
generic paint programs or (for drawings) some wi<strong>de</strong>ly available drawing editor, and that is suitable for input to text formatters or for<br />
149
150 C. GNU FREE DOCUMENTATION LICENSE<br />
automatic translation to a variety of formats suitable for input to text formatters. A copy ma<strong>de</strong> in an otherwise Transparent file format<br />
whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by rea<strong>de</strong>rs is not Transparent.<br />
An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.<br />
Examples of suitable formats for Transparent copies inclu<strong>de</strong> plain ASCII without markup, Texinfo input format, <strong>La</strong>TeX input format,<br />
SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF <strong>de</strong>signed for human modification.<br />
Examples of transparent image formats inclu<strong>de</strong> PNG, XCF and JPG. Opaque formats inclu<strong>de</strong> proprietary formats that can be read<br />
and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available,<br />
and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.<br />
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are nee<strong>de</strong>d to hold, legibly, the material<br />
this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text<br />
near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.<br />
The “publisher” means any person or entity that distributes copies of the Document to the public.<br />
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses<br />
following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”,<br />
“Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document<br />
means that it remains a section “Entitled XYZ” according to this <strong>de</strong>finition.<br />
The Document may inclu<strong>de</strong> Warranty Disclaimers next to the notice which states that this License applies to the Document. These<br />
Warranty Disclaimers are consi<strong>de</strong>red to be inclu<strong>de</strong>d by reference in this License, but only as regards disclaiming warranties: any other<br />
implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.<br />
2. VERBATIM COPYING<br />
You may copy and distribute the Document in any medium, either commercially or noncommercially, provi<strong>de</strong>d that this License, the<br />
copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other<br />
conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of<br />
the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number<br />
of copies you must also follow the conditions in section 3.<br />
You may also lend copies, un<strong>de</strong>r the same conditions stated above, and you may publicly display copies.<br />
3. COPYING IN QUANTITY<br />
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and<br />
the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover<br />
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly i<strong>de</strong>ntify<br />
you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible.<br />
You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the<br />
Document and satisfy these conditions, can be treated as verbatim copying in other respects.<br />
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on<br />
the actual cover, and continue the rest onto adjacent pages.<br />
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either inclu<strong>de</strong> a machine-readable<br />
Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general<br />
network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free<br />
of ad<strong>de</strong>d material. If you use the latter option, you must take reasonably pru<strong>de</strong>nt steps, when you begin distribution of Opaque copies in<br />
quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you<br />
distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.<br />
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to<br />
give them a chance to provi<strong>de</strong> you with an updated version of the Document.<br />
4. MODIFICATIONS<br />
You may copy and distribute a Modified Version of the Document un<strong>de</strong>r the conditions of sections 2 and 3 above, provi<strong>de</strong>d that you<br />
release the Modified Version un<strong>de</strong>r precisely this License, with the Modified Version filling the role of the Document, thus licensing<br />
distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the
C. GNU FREE DOCUMENTATION LICENSE 151<br />
Modified Version:<br />
A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions<br />
(which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous<br />
version if the original publisher of that version gives permission.<br />
B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified<br />
Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five),<br />
unless they release you from this requirement.<br />
C. State on the Title page the name of the publisher of the Modified Version, as the publisher.<br />
D. Preserve all the copyright notices of the Document.<br />
E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.<br />
F. Inclu<strong>de</strong>, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version<br />
un<strong>de</strong>r the terms of this License, in the form shown in the Ad<strong>de</strong>ndum below.<br />
G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license<br />
notice.<br />
H. Inclu<strong>de</strong> an unaltered copy of this License.<br />
I. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and<br />
publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one<br />
stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item <strong>de</strong>scribing the Modified<br />
Version as stated in the previous sentence.<br />
J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and<br />
likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History”<br />
section. You may omit a network location for a work that was published at least four years before the Document itself, or if the<br />
original publisher of the version it refers to gives permission.<br />
K. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section<br />
all the substance and tone of each of the contributor acknowledgements and/or <strong>de</strong>dications given therein.<br />
L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent<br />
are not consi<strong>de</strong>red part of the section titles.<br />
M. Delete any section Entitled “Endorsements”. Such a section may not be inclu<strong>de</strong>d in the Modified Version.<br />
N. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.<br />
O. Preserve any Warranty Disclaimers.<br />
If the Modified Version inclu<strong>de</strong>s new front-matter sections or appendices that qualify as Secondary Sections and contain no material<br />
copied from the Document, you may at your option <strong>de</strong>signate some or all of these sections as invariant. To do this, add their titles to the<br />
list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.<br />
You may add a section Entitled “Endorsements”, provi<strong>de</strong>d it contains nothing but endorsements of your Modified Version by various<br />
parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative <strong>de</strong>finition of a<br />
standard.<br />
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end<br />
of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be ad<strong>de</strong>d by<br />
(or through arrangements ma<strong>de</strong> by) any one entity. If the Document already inclu<strong>de</strong>s a cover text for the same cover, previously ad<strong>de</strong>d by<br />
you or by arrangement ma<strong>de</strong> by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on<br />
explicit permission from the previous publisher that ad<strong>de</strong>d the old one.<br />
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert<br />
or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS
152 C. GNU FREE DOCUMENTATION LICENSE<br />
You may combine the Document with other documents released un<strong>de</strong>r this License, un<strong>de</strong>r the terms <strong>de</strong>fined in section 4 above for<br />
modified versions, provi<strong>de</strong>d that you inclu<strong>de</strong> in the combination all of the Invariant Sections of all of the original documents, unmodified,<br />
and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.<br />
The combined work need only contain one copy of this License, and multiple i<strong>de</strong>ntical Invariant Sections may be replaced with a single<br />
copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by<br />
adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make<br />
the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.<br />
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled<br />
“History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must <strong>de</strong>lete all<br />
sections Entitled “Endorsements”.<br />
5. COLLECTIONS OF DOCUMENTS<br />
You may make a collection consisting of the Document and other documents released un<strong>de</strong>r this License, and replace the individual<br />
copies of this License in the various documents with a single copy that is inclu<strong>de</strong>d in the collection, provi<strong>de</strong>d that you follow the rules of<br />
this License for verbatim copying of each of the documents in all other respects.<br />
You may extract a single document from such a collection, and distribute it individually un<strong>de</strong>r this License, provi<strong>de</strong>d you insert a copy<br />
of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.<br />
6. AGGREGATION WITH INDEPENDENT WORKS<br />
A compilation of the Document or its <strong>de</strong>rivatives with other separate and in<strong>de</strong>pen<strong>de</strong>nt documents or works, in or on a volume of a<br />
storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights<br />
of the compilation’s users beyond what the individual works permit. When the Document is inclu<strong>de</strong>d in an aggregate, this License does<br />
not apply to the other works in the aggregate which are not themselves <strong>de</strong>rivative works of the Document.<br />
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half<br />
of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the<br />
electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole<br />
aggregate.<br />
7. TRANSLATION<br />
Translation is consi<strong>de</strong>red a kind of modification, so you may distribute translations of the Document un<strong>de</strong>r the terms of section 4.<br />
Replacing Invariant Sections with translations requires special permission from their copyright hol<strong>de</strong>rs, but you may inclu<strong>de</strong> translations<br />
of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may inclu<strong>de</strong> a translation of this<br />
License, and all the license notices in the Document, and any Warranty Disclaimers, provi<strong>de</strong>d that you also inclu<strong>de</strong> the original English<br />
version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the<br />
original version of this License or a notice or disclaimer, the original version will prevail.<br />
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its<br />
Title (section 1) will typically require changing the actual title.<br />
8. TERMINATION<br />
You may not copy, modify, sublicense, or distribute the Document except as expressly provi<strong>de</strong>d un<strong>de</strong>r this License. Any attempt<br />
otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights un<strong>de</strong>r this License.<br />
However, if you cease all violation of this License, then your license from a particular copyright hol<strong>de</strong>r is reinstated (a) provisionally,<br />
unless and until the copyright hol<strong>de</strong>r explicitly and finally terminates your license, and (b) permanently, if the copyright hol<strong>de</strong>r fails to<br />
notify you of the violation by some reasonable means prior to 60 days after the cessation.<br />
Moreover, your license from a particular copyright hol<strong>de</strong>r is reinstated permanently if the copyright hol<strong>de</strong>r notifies you of the violation<br />
by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright<br />
hol<strong>de</strong>r, and you cure the violation prior to 30 days after your receipt of the notice.<br />
Termination of your rights un<strong>de</strong>r this section does not terminate the licenses of parties who have received copies or rights from you<br />
un<strong>de</strong>r this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material
C. GNU FREE DOCUMENTATION LICENSE 153<br />
does not give you any rights to use it.<br />
9. FUTURE REVISIONS OF THIS LICENSE<br />
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time.<br />
Such new versions will be similar in spirit to the present version, but may differ in <strong>de</strong>tail to address new problems or concerns. See<br />
http://www.gnu.org/copyleft/.<br />
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of<br />
this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version<br />
or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version<br />
number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document<br />
specifies that a proxy can <strong>de</strong>ci<strong>de</strong> which future versions of this License can be used, that proxy’s public statement of acceptance of a version<br />
permanently authorizes you to choose that version for the Document.<br />
10. RELICENSING<br />
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wi<strong>de</strong> Web server that publishes copyrightable works and<br />
also provi<strong>de</strong>s prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A<br />
“Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC<br />
site.<br />
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a notfor-profit<br />
corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license<br />
published by that same organization.<br />
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.<br />
An MMC is “eligible for relicensing” if it is licensed un<strong>de</strong>r this License, and if all works that were first published un<strong>de</strong>r this License<br />
somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant<br />
sections, and (2) were thus incorporated prior to November 1, 2008.<br />
The operator of an MMC Site may republish an MMC contained in the site un<strong>de</strong>r CC-BY-SA on the same site at any time before<br />
August 1, 2009, provi<strong>de</strong>d the MMC is eligible for relicensing.
Bibliografía<br />
[Arg93]<br />
D. Arganbright. Practical Handbook of Spreadsheet Curves and Geometric Constructions.<br />
CRC Press, 1993.<br />
[BBvB + 01] K. Beck, M. Beedle, A. van Bennekum, A. Cockburn, W. Cunningham, M. Fowler,<br />
J. Grenning, J. Highsmith, A. Hunt, R. Jeffries, J. Kern, B. Marick, R. C. Martin, S. Mellor,<br />
K. Schwaber, J. Sutherland, y D. Thomas. Manifesto for Agile Software Development.<br />
2001. Disponible en: http://agilemanifesto.org/.<br />
[BFJLP06] K. R. Baker, L. Foster-Johnson, B. <strong>La</strong>wson, y S. G. Powell. A Survey of<br />
MBA Spreadsheet Users. Spreadsheet Engineering Research Project, 2006. Disponible<br />
en: http://mba.tuck.dartmouth.edu/spreadsheet/product_<br />
pubs_files/SurveyPaper.doc.<br />
[BFJLP07] K. R. Baker, L. Foster-Johnson, B. <strong>La</strong>wson, y S. G. Powell. Spreadsheet Risk,<br />
Awareness, and Control. Spreadsheet Engineering Research Project, 2007. Disponible<br />
en: http://mba.tuck.dartmouth.edu/spreadsheet/product_<br />
pubs_files/SSrisk.doc.<br />
[Bra]<br />
H.Merijn Brand. Spreadsheet::Read. Disponible en: http://search.cpan.org/<br />
~hmbrand/Spreadsheet-Read-0.41/Read.pm.<br />
[Byt] ByteScout. Spreadsheet SDK. Disponible en: http://www.bytescout.com/<br />
products/<strong>de</strong>veloper/spreadsheetsdk/bytescoutspreadsheetsdk.<br />
html.<br />
[Car10] Carlos Blé. Diseño Ágil con TDD. jan 2010. Disponible en: http://www.<br />
dirigidoportests.com/el-libro.<br />
[com]<br />
GlassFish community. JAX-WS. Disponible en: http://jax-ws.java.net/.<br />
[Cor84] Lotus Development Corporation. Worksheet File Format From LOTUS. Diciembre<br />
1984. Disponible en: http://www.schnarff.com/file-formats/in<strong>de</strong>x.<br />
html.<br />
[CPA]<br />
[CTC06]<br />
CPAN. CPAN. Disponible en: http://search.cpan.org/.<br />
P.E. Craig T. Christy. Engineering with the Spreadsheet: Structural Engieering Templates<br />
Using Excel. ASCE, 2006.<br />
155
156 BIBLIOGRAFÍA<br />
[dIU07] Escuela Superior <strong>de</strong> Informática (UCLM). Normativa <strong>de</strong>l Proyecto Fin <strong>de</strong> Carrera.<br />
2007. Disponible en: http://www.esi.uclm.es:8081/www/documentos/<br />
Normativas/NormativaPFC2007.pdf.<br />
[Fab]<br />
[Foua]<br />
S. Faber. Mockito. Disponible en: http://mockito.org/.<br />
The Apache Software Foundation. The Apache POI Project. Disponible en: http:<br />
//poi.apache.org/.<br />
[Foub] The Apache Software Foundation. Apache Subversion. Disponible en: http://<br />
subversion.apache.org/.<br />
[Fouc]<br />
The Apache Software Foundation. Apache Tomcat. Disponible en: http://tomcat.<br />
apache.org/.<br />
[Foud] The Apache Software Foundation. POI-HSSF and POI-XSSF - Java API To Access<br />
Microsoft Excel Format Files. Disponible en: http://poi.apache.org/<br />
spreadsheet/in<strong>de</strong>x.html.<br />
[Foue]<br />
[Fre92]<br />
[Gou]<br />
[Gro]<br />
[ink]<br />
The Eclipse Foundation. Eclipse. Disponible en: http://www.eclipse.org/.<br />
H. Freiser. Concepts & Calculations in Analytical Chemistry: A Spreadsheet Approach.<br />
CRC Press, 1992.<br />
J.M. Gouarne. OpenOffice::OODoc. Disponible en: http://search.cpan.org/<br />
~jmgdoc/OpenOffice-OODoc-2.125/OODoc/Intro.pod.<br />
European Spreadsheet Risks Interest Group. Spreadsheet Horror Stories. Disponible<br />
en: www.eusprig.org/stories.htm.<br />
Inkscape. Disponible en: http://inkscape.org/.<br />
[Jay] Jayway. PowerMock. Disponible en: http://co<strong>de</strong>.google.com/p/<br />
powermock/.<br />
[KB]<br />
E. Gamma K. Beck. JUnit. Disponible en: http://www.junit.org/.<br />
[Kni07] H. Kniberg. Scrum y XP <strong>de</strong>s<strong>de</strong> las Trincheras. Cómo hacemos Scrum. C4Media, 2007.<br />
[LBPFJ07] B. <strong>La</strong>wson, K. R. Baker, S. G. Powell, y L. Foster-Johnson. A comparison<br />
of spreadsheet users with different levels of experience. Omega, 2007. Disponible<br />
en: http://mba.tuck.dartmouth.edu/spreadsheet/product_<br />
pubs_files/Comparison.pdf.<br />
[McN] J. McNamara. Spreadsheet::WriteExcel. Disponible en: http://search.<br />
cpan.org/~jmcnamara/Spreadsheet-WriteExcel-2.37/lib/<br />
Spreadsheet/WriteExcel.pm.<br />
[Mic07] Microsoft. How to automate Excel from C++ without using MFC or #import. may 2007.<br />
Disponible en: http://support.microsoft.com/kb/216686/en-us.
BIBLIOGRAFÍA 157<br />
[Mic08a] Microsoft. Microsoft Office Excel 2007 Binary File Format Specification [*.xlsb].<br />
Junio 2008. Disponible en: http://www.microsoft.com/interop/docs/<br />
officebinaryformats.mspx.<br />
[Mic08b] Microsoft. Microsoft Office Excel 97-2007 Binary File Format Specification [*.xls<br />
(97-2007) format]. Junio 2008. Disponible en: http://www.microsoft.com/<br />
interop/docs/officebinaryformats.mspx.<br />
[Mic08c]<br />
[Mic10a]<br />
Microsoft. Office Automation Using Visual C++. mar 2008. Disponible en: http:<br />
//support.microsoft.com/kb/196776/EN-US/.<br />
Microsoft. MS-OODF2: Office Implementation Information for ODF 1.1 Version 2 Standard<br />
Compliance. Junio 2010. Disponible en: http://msdn.microsoft.com/<br />
en-us/library/ee908651(v=office.12).aspx.<br />
[Mic10b] Microsoft. MS-XLSX: Excel Extensions to the Office Open XML SpreadsheetML<br />
File Format (.xlsx) Specification. Junio 2010. Disponible en: http://msdn.<br />
microsoft.com/en-us/library/dd922181(v=office.12).aspx.<br />
[NR99] J. Batson N. Read. Spreadsheet Mo<strong>de</strong>lling Best Practice. Business Dynamics, apr 1999.<br />
Disponible en: http://www.eusprig.org/smbp.pdf.<br />
[oas]<br />
[OAS07]<br />
OASIS Consortium. Disponible en: http://www.oasis-open.org.<br />
OASIS. Open Document Format for Office Applications (OpenDocument) Specification<br />
v1.1. Febrero 2007. Disponible en: http://docs.oasis-open.org/office/<br />
v1.1/OS/OpenDocument-v1.1.pdf.<br />
[OAS10] OASIS. Open Document Format for Office Applications (OpenDocument)<br />
Version 1.2 (Committee Draft 04-Rev 09). Junio 2010. Disponible en:<br />
http://www.oasis-open.org/committees/download.php/38239/<br />
OpenDocument-v1.2-part1-cd04-rev09.odt.<br />
[OKvLV]<br />
O. Ojala, K. Karlsson, B. von Loesch, y T. Arne Vestb. Texlipse. Disponible en: http:<br />
//texlipse.sourceforge.net/.<br />
[ooo] OpenOffice.org Draw. Disponible en: http://www.openoffice.org/<br />
product/draw.html.<br />
[ope]<br />
[Oraa]<br />
[Orab]<br />
[Orac]<br />
OpenOffice.org. Disponible en: http://www.openoffice.org.<br />
Oracle. JDK Java Development Kit. Disponible en: http://www.oracle.com/<br />
technetwork/java/javase/downloads/in<strong>de</strong>x.html.<br />
Oracle. NetBeans IDE. Disponible en: http://netbeans.org/.<br />
Oracle. OpenOffice.org Calc. Disponible en: http://www.openoffice.org/<br />
product/calc.html.
158 BIBLIOGRAFÍA<br />
[Orad]<br />
Oracle. OpenOffice.org SDK. Disponible en: http://download.openoffice.<br />
org/sdk/.<br />
[Ora10] Oracle. OpenOffice.org Developer’s Gui<strong>de</strong>. aug 2010. Disponible en:<br />
http://wiki.services.openoffice.org/wiki/Documentation/<br />
DevGui<strong>de</strong>/OpenOffice.org_Developers_Gui<strong>de</strong>.<br />
[Pal07]<br />
[Pro]<br />
J. Palacio. Flexibilidad con Scrum. safe creative, oct 2007. Disponible en: http:<br />
//www.navegapolis.net/files/Flexibilidad_con_Scrum.pdf.<br />
The <strong>La</strong>Tex3 Project. <strong>La</strong>Tex. Disponible en: http://www.latex-project.org/.<br />
[RA08] M. Erwig R. Abraham. Test-Driven Goal-Directed Debugging in Spreadsheets.<br />
2008. Disponible en: http://web.engr.oregonstate.edu/~erwig/<br />
papers/TestDrivenDebugging_VLHCC08.pdf.<br />
[RA09] M. Erwig R. Abraham, M. M. Burnett. Spreadsheet Programming. 2009.<br />
Disponible en: http://web.engr.oregonstate.edu/~erwig/papers/<br />
SpreadsheetProgramming_ECSE09.pdf.<br />
[SL99]<br />
S.E. Margolis S.J. Liebowitz. Winners, Losers, and Microsoft: How Technology Markets<br />
Choose Products. In<strong>de</strong>pen<strong>de</strong>nt Institute, may 1999.<br />
[Sof] GemBox Software. GemBox.Spreadsheet. Disponible en: http://www.<br />
gemboxsoftware.com/GBSpreadsheet.htm.<br />
[Spr] Groovy Community SpringSource. Groovy. Disponible en: http://groovy.<br />
co<strong>de</strong>haus.org/.<br />
[Tak] K. Takanori. Spreadsheet::ParseExcel. Disponible en: http://search.cpan.<br />
org/~kwitknr/Spreadsheet-ParseExcel-0.2602/ParseExcel.pm.<br />
[Tea]<br />
[umb]<br />
The Gimp Team. Gimp. Disponible en: http://www.gimp.org/.<br />
Umbrello UML Mo<strong>de</strong>ller. Disponible en: http://uml.sourceforge.net/.<br />
[Wal10] J. Walkenbach. Excel 2010 Power Programming with VBA. Wiley Publishing, 2010.