28.01.2015 Views

opensheet - Grupo ARCO - Universidad de Castilla-La Mancha

opensheet - Grupo ARCO - Universidad de Castilla-La Mancha

opensheet - Grupo ARCO - Universidad de Castilla-La Mancha

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

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.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!