0% encontró este documento útil (0 votos)
54 vistas286 páginas

Documentacion Final

Este documento presenta un proyecto de fin de carrera para el desarrollo de una plataforma groupware. El proyecto tiene como objetivo crear un marco de trabajo para aplicaciones colaborativas mediante el uso de tecnologías como RMI, Jini y JavaSpaces. El documento incluye un análisis del estado del arte, las tecnologías utilizadas, los requisitos funcionales y no funcionales, el análisis y diseño de la arquitectura y subsistemas propuestos.

Cargado por

Sonia Rios
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
54 vistas286 páginas

Documentacion Final

Este documento presenta un proyecto de fin de carrera para el desarrollo de una plataforma groupware. El proyecto tiene como objetivo crear un marco de trabajo para aplicaciones colaborativas mediante el uso de tecnologías como RMI, Jini y JavaSpaces. El documento incluye un análisis del estado del arte, las tecnologías utilizadas, los requisitos funcionales y no funcionales, el análisis y diseño de la arquitectura y subsistemas propuestos.

Cargado por

Sonia Rios
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 286

Proyecto Fin de Carrera

Desarrollo de un marco de trabajo para la creación de aplicaciones colaborativas.


Creación de una plataforma groupware.

Autores
Ana Belén Pelegrina Ortiz
Carlos Rodríguez Domínguez

Tutor Ingeniería informática


José Luis Garrido Bullejos Convocatoria: Junio 2008
Índice de contenido
Prólogo: Una visión general del proyecto..............................................................................6
1.Introducción........................................................................................................................1
1.1.Trabajo colaborativo asistido por ordenador ............................................................3
1.2.Groupware..................................................................................................................6
1.3.Objetivos ....................................................................................................................8
2.Estado del arte.................................................................................................................11
2.1.Metodología AMENITIES..........................................................................................11
2.2.Habanero..................................................................................................................12
2.3.La propuesta PageSpace.........................................................................................14
2.4.BSCW.......................................................................................................................16
2.5.Google Docs and Spreadsheets...............................................................................17
2.6.MOODLE..................................................................................................................18
2.7.TOP: Una plataforma para el desarrollo de Interfaces y Aplicaciones colaborativas
sobre Web. ......................................................................................................................19
3.Tecnologías......................................................................................................................20
3.1.Swing........................................................................................................................20
3.2.Java look & feel........................................................................................................21
3.3.RMI...........................................................................................................................22
3.4.JINI ...........................................................................................................................25
3.5.JavaSpaces..............................................................................................................30
3.6.MySQL......................................................................................................................38
3.7.PDFRenderer............................................................................................................39
4.Especificación y Análisis de Requisitos...........................................................................40
4.1.Descripción del sistema ...........................................................................................40
4.2.Requisitos funcionales..............................................................................................42
4.3.Requisitos No Funcionales ......................................................................................43
4.4.Análisis de los requerimientos para el sistema........................................................46
4.4.1. Lista de Casos de Uso ....................................................................................................46
4.4.2. Diagramas de Casos de Uso ...........................................................................................49
4.4.3. Operaciones del sistema identificadas ...........................................................................50
5.Análisis.............................................................................................................................51
5.1.Identificación de clases, atributos y relaciones........................................................51
5.2.Diagrama de clases estático....................................................................................53
5.3.Modelado del comportamiento externo del sistema.................................................54
6.Diseño general del sistema..............................................................................................68
6.1.Diseño arquitectónico...............................................................................................69
6.2.Diseño de la interfaz gráfica.....................................................................................73
6.3.Decisiones de diseño tomadas para la consecución de los objetivos del sistema..80
6.4.Subsistemas identificados........................................................................................83
7.Diseño de subsistemas....................................................................................................84
7.1. Subsistemas específicos del framework.................................................................84
7.1.1 Gestión de eventos del sistema.......................................................................................85
7.1.2 Gestión del repositorio de datos del sistema...................................................................95

Proyecto Fin de Carrera | 1


7.1.3 Gestión de metainformación de aplicaciones................................................................103
7.1.4 Gestión de la metainformación de ficheros...................................................................111
7.1.5. Subsistema de transmisión de datos.............................................................................119
7.2. Subsistemas específicos para la creación de la plataforma.................................123
7.2.1. Subsistema de Gestión de Documentos.......................................................................123
7.2.2. Subsistema de Edición Compartida de Documentos...................................................131
7.2.3. Subsistema de plugins..................................................................................................139
7.2.4. Subsistema de videoconferencia..................................................................................154
7.2.5. Aplicación cliente........................................................................................................166
8.Componentes gráficos reutilizables (Beans).................................................................173
8.1.DcomponenteBase.................................................................................................174
8.2.Hebras procesadoras.............................................................................................180
8.3.Clases captadoras..................................................................................................181
8.4.Componentes implementados listos para usarse..................................................199
8.5.Menús.....................................................................................................................213
8.6.Sincronización de componentes.............................................................................215
8.7.Telepunteros (Gestor de Mouses Remotos)...........................................................217
9. Manual del desarrollador..............................................................................................219
10. Apéndices...................................................................................................................234
A. Casos de uso detallados...........................................................................................234
B. Histórico del diseño de la interfaz gráfica de usuario...............................................252
C. Manual de operación.................................................................................................256
D. Manual de usuario.....................................................................................................259
E. Dificultades encontradas...........................................................................................262
F. Pruebas de Rendimiento...........................................................................................268
G. Bibliografía................................................................................................................272

Índice de ilustraciones
Ilustración 1: Asociaciones Tiempo/Lugar para Groupware................................................................4
Ilustración 2: Modelo de la Metodología AMENITIES.....................................................................12
Ilustración 3: Implementación típica de una aplicación RMI. Desde Java 2 SDK, Standard Edition,
v1.2 no hay necesidad de Skeleton.....................................................................................................22
Ilustración 4: Capas en Jini.................................................................................................................25
Ilustración 5: Arquitectura de una aplicación que usa JavaSpaces....................................................34
Ilustración 6: Casos de uso para el subsistema de documentos..........................................................49
Ilustración 7: Diagrama de casos de uso para el subsistema Plugin...................................................49
Ilustración 8: Diagrama de casos de uso para el subsistema Usuarios...............................................49
Ilustración 9: Diagrama de clases estáticos........................................................................................53
Ilustración 10: Diagrama de colaboración para la operación abrir documento..................................60
Ilustración 11: Diagrama de colaboración para la operación realizarAnotacion................................60
Ilustración 12: Diagrama de colaboración para la operación eliminarAnotación..............................61
Ilustración 13: Diagrama de colaboración para la operación imprimir..............................................61
Ilustración 14: Diagrama de colaboración para la operación guardarDocumento.............................61
Ilustración 15: Diagrama de colaboración para la operación subirDocumento..................................62
Ilustración 16: Diagrama de colaboración para la operación crearCarpeta........................................62

Proyecto Fin de Carrera | 2


Ilustración 17: Diagrama de colaboración para la operación eliminarDocumento............................62
Ilustración 18: Diagrama de colaboración para la operación moverDocumento...............................63
Ilustración 19: Diagrama de colaboración para la operación obtenerPropiedades.............................63
Ilustración 20: Diagrama de colaboración para la operación cambiarNombre..................................63
Ilustración 21: Diagrama de colaboración para la operación cambiarPermisos.................................64
Ilustración 22: Diagrama de colaboración para la operación iniciarChat..........................................64
Ilustración 23: Diagrama de colaboración para la operación enviarMensaje.....................................64
Ilustración 24: Diagrama de colaboración para la operación iniciarChatPrivado..............................65
Ilustración 25: Diagrama de colaboración para la operación enviarMensajePrivado........................65
Ilustración 26: Diagrama de colaboración para la operación iniciarVC............................................65
Ilustración 27: Diagrama de colaboración para la operación cambiarRol..........................................66
Ilustración 28: Diagrama de colaboración para la operación obtenerListaPlugins............................66
Ilustración 29: Diagrama de colaboración para la operación cambiarVisibilidad..............................66
Ilustración 30: Diagrama de colaboración para la operación agregarPlugin......................................67
Ilustración 31: Diagrama de colaboración para la operación eliminarPlugin....................................67
Ilustración 32: Esquema general del sistema......................................................................................70
Ilustración 33: Esquema general de una aplicación cliente................................................................70
Ilustración 34: Arquitectura del sistema.............................................................................................71
Ilustración 35: Diagrama de paquetes del sistema.............................................................................71
Ilustración 36: Diagrama de despliegue del sistema..........................................................................72
Ilustración 37: Captura de la pantalla principal de la plataforma BSCW .........................................75
Ilustración 38: Versión definitiva de la interfaz principal de la aplicación .......................................76
Ilustración 39: Versión revisada de la interfaz...................................................................................77
Ilustración 40: Ventana principal de la aplicación..............................................................................78
Ilustración 41: Imagen del primer prototipo del editor......................................................................79
Ilustración 42: Diseño definitivo del interfaz del editor de documentos............................................79
Ilustración 43: Diagrama de secuencia para el envío de eventos.......................................................88
Ilustración 44: Diagrama de secuencia de la inicialización del DConector.......................................89
Ilustración 45: Ventana de login y ventana de sincronización...........................................................90
Ilustración 46: Diagrama de clases del subsistema............................................................................94
Ilustración 47: Diagrama de clases del subsistema de gestión del repositorio...................................98
Ilustración 48: Diagrama Entidad/Relación del repositorio.............................................................101
Ilustración 49: Esquema arquitectónico de el subsistema de gestión de la metainformación de la
aplicación..........................................................................................................................................103
Ilustración 50: Diagrama de estados para el monitor del cliente de metainformación.....................106
Ilustración 51: Ventana del diálogo de metainformación.................................................................109
Ilustración 52: Diagrama de clases del subsistema de gestión de metainformación........................110
Ilustración 53: Esquema arquitectónico del subsistema...................................................................111
Ilustración 54: Diagrama de estados para el monitor.......................................................................113
Ilustración 55: Diagrama de clases del subsistema de gestión de metainformación de ficheros.....118
Ilustración 56: Diagrama de clases para el subsistema de Transmisión de datos.............................122
Ilustración 57: Esquema arquitectónico del subsistema...................................................................124
Ilustración 58: Diagrama de clases del subsistema Documento.......................................................130
Ilustración 59: Diagrama de clases para TokenFichero....................................................................133
Ilustración 60: Esquema de funcionamiento del mecanismos de apertura de documentos..............134
Ilustración 61: Esquema de funcionamiento del mecanismos de apertura de documentos..............135
Ilustración 62: Aspecto del editor.....................................................................................................136
Ilustración 63: Barra de controles.....................................................................................................137

Proyecto Fin de Carrera | 3


Ilustración 64: Barra de estado.........................................................................................................137
Ilustración 65: Diagrama de clases para las figuras.........................................................................138
Ilustración 66: Diagrama de estados para las hebras que esperan la sincronización con
PluginContainer................................................................................................................................144
Ilustración 67: Diagrama de clases para el subsistema CalculoParalelo..........................................148
Ilustración 68: Plugin Chat...............................................................................................................149
Ilustración 69: Plugin gestor de plugins...........................................................................................150
Ilustración 70: Plugin Pizarra Compartida.......................................................................................151
Ilustración 71: Lista de aplicaciones................................................................................................152
Ilustración 72: Diagrama de claes del subsistema Plugin................................................................153
Ilustración 73: Esquema de funcionamiento de la transmisión de vídeo.........................................157
Ilustración 74: Esquema del panel de videoconferencia..................................................................158
Ilustración 75: Panel de configuración de audio..............................................................................160
Ilustración 76: Protocolo Handshake para la transmisión de audio.................................................162
Ilustración 77: Panel de configuración de la conexión para la transmision del audio......................162
Ilustración 78: Ventana de videoconferencia....................................................................................163
Ilustración 79: Diagrama de clases para el sistema videoconferencia..............................................165
Ilustración 80: Esquema básico de una aplicación creada haciendo uso de nuestro Framework.....166
Ilustración 81: Ventana de composición de mensajes asíncronos....................................................168
Ilustración 82: Ventana de gestión de la metainformación de los documentos................................171
Ilustración 83: Ventana Principal de la aplicación y susbistemas involucrados ..............................172
Ilustración 84: Diagrama de clases para DComponenteBase...........................................................176
Ilustración 85: Diagrama de clases para DJListEvent......................................................................183
Ilustración 86: Diagrama de clases para DJListListener..................................................................184
Ilustración 87: Diagrama de clases para DJComboBoxEvent..........................................................184
Ilustración 88: Diagrama de clases para DJComboBoxListener......................................................186
Ilustración 89: Diagrama de clases para DJButtonEvent.................................................................187
Ilustración 90: Diagrama de clases para DJButtonListener.............................................................188
Ilustración 91: Diagrama de clases para DJToggleButtonEvent......................................................188
Ilustración 92: Diagrama de clases para DJToggleButtonEvent......................................................189
Ilustración 93: Diagrama de clases para DJCheckBoxEvent...........................................................190
Ilustración 94: Diagrama de clases para DJCheckBoxListener.......................................................191
Ilustración 95: Diagrama de clases para DJTextFieldEvent.............................................................192
Ilustración 96: Diagrama de clases para DJTextFieldListener.........................................................193
Ilustración 97: Diagrama de clases para DJTreeEvent.....................................................................194
Ilustración 98: Diagrama de clases para DJTreeListener................................................................195
Ilustración 99: Diagrama de clases para DJMenuEvent...................................................................196
Ilustración 100: Diagrama de clases para DJMenuListener.............................................................197
Ilustración 101: Diagrama de clases para DJMenuItemEvent.........................................................197
Ilustración 102: Diagrama de clases para DJMenuListener.............................................................198
Ilustración 103: Diagrama de secuencia para ArbolDocumentos....................................................207
Ilustración 104: Diagrama de clases para el subsistema...................................................................211
Ilustración 105: Esquema del Glass Pane.........................................................................................218
Ilustración 106: Visualización de los elementos involucrados en el proyecto.................................220
Ilustración 107: Esquema gráfico del chat a desarrollar..................................................................222
Ilustración 108: Imagen del chat......................................................................................................225
Ilustración 109: Pantalla principal....................................................................................................231
Ilustración 110: Ventana del chat......................................................................................................232

Proyecto Fin de Carrera | 4


Ilustración 111: Gestor de plugins....................................................................................................233
Ilustración 112: Captura de pantalla de EyeOS, que ilustraría la idea básica del primer diseño de la
GUI...................................................................................................................................................252
Ilustración 113: Primer prototipo de la interfaz................................................................................253
Ilustración 114: Diseño de la interfaz de ventana principal de la aplicación (versión 2) ................254
Ilustración 115: Tercer prototipo de la interfaz................................................................................255
Ilustración 116: Tercer prototipo de la interfaz revisado..................................................................255
Ilustración 117: Pantalla principal de la aplicación..........................................................................259
Ilustración 118: Consumo de memoria al lanzar los servicios (JavaSpace y Transaction Manager)
..........................................................................................................................................................268
Ilustración 119: Consumo de memoria tras lanzar el servidor de ficheros.......................................269
Ilustración 120: Consumo de memoria tras lanzar el servidor de metainformación........................269
Ilustración 121: Comsumo de memoria tras lanzar una aplicación cliente......................................269
Ilustración 122: Consumo de memoria tras la apertura de un documento......................................269
Ilustración 123: Uso de la CPU durante la anotación de un documento..........................................270
Ilustración 124: Uso de la red en el arranque de una aplicación cliente..........................................271
Ilustración 125: Uso de la red durante la carga de un documento....................................................271

Índice de tablas
Tabla 3.1.: Arquitectura en capas de RMI..........................................................................................24
Tabla 3.2: Operaciones básias en un espacio de tuplas......................................................................31
Tabla 4.1: Resumen de los casos de uso.............................................................................................48
Tablas 5.1: Contratos del sistema.......................................................................................................59
Tabla 7.1: Métodos públicos de la clase ClienteFicheros.................................................................115
Tabla 7.2: Métodos públicos de la clase abstracta Figura................................................................139
Tabla 8.1: Clases captadoras y eventos asociados............................................................................182
Tabla 8.2: Eventos disponibles para DJTreeEvent DJListEvent......................................................183
Tabla 8.3: Eventos disponibles para DJComboBoxEvent................................................................185
Tabla 8.4: Eventos disponibles para DJButtonEvent........................................................................187
Tabla 8.5: Eventos disponibles para DJToggleButtonEvent............................................................189
Tabla 8.6: Eventos disponibles para DJTreeEvent DJCheckBoxEvent............................................190
Tabla 8.7: Eventos disponibles para DJTextFieldEvent...................................................................192
Tabla 8.8: Eventos disponibles para DJTreeEvent...........................................................................194
Tabla 8.9: Tipos de evento para DFileEvent....................................................................................205
Tabla 8.10: Tipos de evento para DJViewerEvent............................................................................208
Tabla 8.11: Tipos de evento par DJLienzoEvent..............................................................................210
Tabla 8.12: Aspecto de los componentes gráficos según sus permisos............................................212
Tabla 10.1: Especificación detallada de los casos de uso.................................................................251

Proyecto Fin de Carrera | 5


Prólogo: Una visión general del proyecto

A lo largo de éste documento se explicará en detalle el proceso de desarrollo de un marco


de trabajo para la creación de aplicaciones colaborativas, así como un caso de estudio
específico: El soporte a la toma de decisiones. Debido a la complejidad del sistema
realizado, es importante dar una visión general antes de comenzar.

La motivación de éste proyecto son los siguientes hechos:

! Las aplicaciones colaborativas, habitualmente, hacen uso de bibliotecas de un bajo


nivel de abstracción.
! La seguridad no es una prioridad de éstas bibliotecas (se delega la seguridad a las
aplicaciones finales).
! Las aplicaciones suelen escribirse para una tarea específica, con lo que es difícil su
reutilización.
! Las aplicaciones y las bibliotecas suelen escribirse para un SO o dispositivo
concreto.

Si sumamos la superación de los puntos anteriores y la aportación a un sistema de


capacidades de un groupware, awareness (conciencia) y requisitos de calidad, tales como
extensibilidad o facilidad de uso, obtendremos finalmente el resultado obtenido al finalizar
la realización de éste proyecto.

Veamos, punto por punto, y de forma muy general, la solución adoptada para cada uno de
los objetivos marcados para la obtención de las características anteriores.

Para evitar la necesidad de un amplio conocimiento en sistemas distribuidos y acerca de


cuestiones de bajo nivel, el marco de trabajo implementado proporciona una asbtracción
fundamental para la comunicación entre aplicaciones: Los eventos. Un evento tiene
información acerca de sí mismo y acerca del estado del sistema (metainformación). Los
eventos se escribirán en un espacio de comunicaciones, que en nuestro caso será
JavaSpaces. Las aplicaciones que hagan uso del marco de trabajo leerán de éste espacio
éstos eventos y los procesarán. Sobre éste espacio de comunicaciones se crea una
abstracción para que si en un futuro se desea se pueda intercambiar JavaSpaces por otra
tecnología sin tener que cambiar el resto de la implementación del sistema. A ésta
abstracción se le llama DConector y habrá una única instancia en ejecución por cada
aplicación.

Para tener awareness, se ha realizado una combinación de los eventos antes


mencionados y un almacenamiento persistente de la metainformación del sistema:
Usuarios, roles de éstos usuarios y permisos sobre el uso de componentes gráficos en las
aplicaciones. Cada usuario podrá tener varios roles posibles. Se definirá en todo caso un
rol por defecto para cada usuario. En cada momento, un usuario solo podrá tener un rol
entre la lista de roles permitidos para él. Los roles definirán el acceso a ciertos
componentes del sistema o a ciertos documentos compartidos. Para el almacenamiento
persistente, se utiliza una base de datos MySQL. Para facilitar el hecho de que en algún
momento futuro la tecnología de almacenamiento cambie, se han creado abstracciones
sobre ésta, de tal forma que solo existirá una clase implementada que acceda
directamente a MySQL. El resto de clases del sistema harán uso de éste mecanismo de
abstracción para acceder a los datos persistentemente guardados.

Para solucionar el hecho de que el sistema sea extensible, y por tanto se pueda modificar
para la resolución de una tarea específica, siendo por tanto reutilizable, se implementa un
mecanismo de plug-ins. Mediante el marco de trabajo, se permite la implementación de
plug-ins con suma facilidad: Tan solo se deberán implementar tres métodos para que
cualquier aplicación existente o de nueva implementación sea un plug-in en el sistema.

Proyecto Fin de Carrera | 7


Mediante la combinación de éste mecanismo de plug-ins y una aplicación destinada a los
usuarios finales del sistema, a la que llamaremos aplicación cliente (habrá también
aplicaciones servidor, que permitirán gestionar la metainformación del sistema, tanto la
orientada a las aplicaciones como la orientada a documentos compartidos), daremos
soporte a la toma de decisiones y a la posibilidad de adaptar el funcionamiento del
sistema a un problema concreto: Tan solo se deberán crear diversos sets de plug-ins,
según el caso.

Habrá dos métodos de distribución de plug-ins: Mediante la compartición de los ficheros


.jar que los contengan haciendo uso de un espacio de trabajo con ficheros compartidos o
mediante el uso de un mecanismo de versionado. Éste último permite detectar nuevas
versiones de algún plug-in en algún cliente en ejecución y realizar una descarga directa
desde éste.

Se aportan cuatro plug-ins fundamentales, aunque, como se ha comentado con


anterioridad, se podrán implementar y agregar tantos como se desee. Éstos plug-ins
fundamentales son: Un chat, un sistema de videoconferencia (audio y video), una pizarra
para realizar dibujos compartidos entre diversos usuarios y un gestor de plug-ins.
Mediante éste gestor, podremos agregar y eliminar plug-ins al sistema sin necesidad de
copiar los ficheros .jar que los contienen en una ruta concreta.

Hay que destacar el hecho de que los plug-ins pueden interoperar entre sí mediante
eventos. De hecho, el plug-in dedicado al chat permite realizar videoconferencias,
haciendo uso para ello del plug-in de videoconferencia y de un conjunto de eventos que lo
inician.

Para completar el tema de los plug-ins, hay que destacar el hecho de que también se
proporcionan abstracciones para la realización de plug-ins que realicen cálculos paralelos
siguiendo el modelo maestro-esclavo. Se dan abstracciones sobre el maestro, los
esclavos, las tareas y los resultados.

Para que el sistema se pueda considerar un groupware deberemos tener mecanismos de

Proyecto Fin de Carrera | 8


coordinación, comunicación y colaboración.

La coordinación se realiza mediante los eventos descritos con anterioridad.

La colaboración se realiza mediante la compartición de documentos a través de un


espacio de trabajo y la posibilidad de realizar anotaciones compartidas en ellos. Para que
se puedan realizar anotaciones sobre cualquier formato de fichero, sin necesidad de
implementar un sistema de anotación por cada tipo soportado, se ha creado una
abstracción sobre éstos, a la cuál se le llamará simplemente “Documento”. Un Documento
es un conjunto de páginas con anotaciones. Una página será el resultado de la conversión
a imagen de la página correspondiente del formato original. Ésto se consigue gracias a un
mecanismo de filtros de ficheros. Se proporcionan filtros, por defecto, para que conviertan
los formatos texto, pdf e imágenes (los formatos soportados por Java) a la abstracción
Documento. Además, éstos filtros pueden completarse tanto como se desee sin
necesidad de variar la implementación del sistema mediante el uso de plug-ins destinados
a ello. Así mismo, una anotación será una abstracción sobre una figura cualquiera. Se
aportan como figuras para las anotaciones compartidas la línea, el rectángulo, el óvalo, la
mano alzada y el texto. Se podrán definir tantas como se quiera, al igual que con los
filtros, mediante el uso de plug-ins.

En cuanto a la comunicación, queda solventada gracias a los plug-ins de chat de texto y


videoconferencia.

Para que se pueda realizar un uso lo más sencillo posible de cara al desarrollador del
sistema de los eventos y demás abstracciones, se han implementado componentes
gráficos cuyos eventos son distribuidos. Se aportan componentes simples como el botón,
la lista, el cuadro de texto, la etiqueta, etc. y otros más complejos, creados a partir de los
anteriores, como un chat, un árbol de usuarios bajo un cierto rol, un árbol con los
documentos del espacio de trabajo, etc. Todos éstos componentes siguen el modelo de
desarrollo definido por JavaBeans, con lo que su uso se simplifica en entornos de
desarrollo con diseñadores gráficos de GUI's.

Proyecto Fin de Carrera | 9


La seguridad en las aplicaciones se consigue manteniendo un listado de usuarios y sus
respectivas contraseñas. Se implementan también mecanismos de permisos para
documentos compartidos y componentes gráficos que hagan uso de eventos distribuidos.

En cuanto a los documentos, se guardarán permisos tipo UNIX para cada uno de ellos. En
cada aplicación cliente se mostrarán solo los documentos a los que tenga acceso el
usuario que se haya identificado. El resto permanecerán ocultos. Cualquier cambio en los
permisos desde otra aplicación cliente en ejecución se verá reflejado de forma
instantánea en la interfaz gráfica: Aparecerán documentos si nos dan permisos de lectura,
desaparecerán si nos los quitan, si estamos anotando un documento y nos dan o nos
quitan permisos de escritura, se habilitará o deshabilitará un botón de guardado, o, si nos
quitan permisos de lectura, se nos cerrará el sistema de anotación, etc. En cuanto a los
permisos sobre los componentes gráficos, se nos habilitarán o deshabilitarán según los
permisos definidos para cada usuario y rol en la metainformación del sistema. Cualquier
cambio en ésta se verá reflejado instantáneamente en la visualización de los
componentes, al igual que ocurre con los documentos.

Hay que destacar que la implementación de todo el sistema ha seguido un modelo por
capas. Se han definido tres capas: Una física, otra de modelo y otra de interfaz gráfica de
usuario. Se definen interfaces entre la capa física y la de modelo, y entre ésta última y la
de interfaz gráfica, de tal modo que si deseamos cambiar la implementación de cualquier
capa, si mantenemos la interfaz, no deberemos cambiar la implementación del resto del
sistema. Siempre que se ha podido, en cada subsistema, se ha aplicado el patrón de
diseño fachada (Façade).

Para facilitar el uso de los usuarios finales ante un sistema tan complejo se han seguido
varias pautas: Crear una interfaz gráfica lo más simple y ágil posible, y crear scripts de
instalación e inicialización de aplicaciones y servicios (los necesarios para el correcto uso
de JavaSpaces). Éstos scripts hacen más “amigable” la instalación y operación del
sistema. Así mismo, se proveen una serie de scripts para la configuración automática de
la base de datos MySQL que guardará la metainformación del sistema.

Proyecto Fin de Carrera | 10


Por último, aunque no menos importante, la portabilidad total del sistema se ha
conseguido gracias a la implementación mediante el uso del lenguaje de programación
Java, con lo que será ejecutable en cualquier SO o dispositivo con soporte para la
máquina virtual de éste lenguaje, incluido, por supuesto, móviles.

Gracias a la combinación de las diversas tecnologías empleadas, por último, hay que
destacar el hecho de que la aplicación cliente actuará de una forma parecida a un
hardware “plug and play”: Abre la aplicación en una red concreta y automáticamente
obtendrás de ella sus plug-ins, usuarios, roles, documentos, etc. Además, aportarás las
datos que tuvieras con anterioridad a esa red.

En las secciones de ésta documentación se comentarán con detalle los aspectos


anteriormente mencionados.

Proyecto Fin de Carrera | 11


1. Introducción

El software colaborativo (también conocido como groupware o sistemas con soporte


al trabajo en grupo) es un software diseñado para ayudar en la obtención de una serie
de objetivos a las personas involucradas en una tarea común.

Dentro de ésta categoría de software se encuentra el e-mail, los calendarios compartidos,


los chats, los wiki's, etc.

Para comprender que tecnologías deberemos usar para la creación de software


colaborativo deberemos comprender que mecanismos usamos las personas para
interaccionar.

Existen tres formas fundamentales de interacción entre humanos: Conversaciones,


transacciones y colaboraciones.

La interacción por conversación es un intercambio de información entre dos o más


participantes, donde el propósito fundamental es el descubrimiento de información o la
mejora de la relación entre ellos. En principio, se puede considerar que es un intercambio
libre y sin restricciones de información. En la mayoría de los casos, tecnológicamente, nos
bastará con una sistema de telefonía, mensajería instantánea o e-mail para implementar
una interacción por conversación.
La interacción mediante transacciones se basa en el intercambio de entidades de
transacción, cuya función principal es la de alterar la relación entre varios participantes.
Una entidad de transacción es un elemento relativamente estable en forma y que
restringe o redefine la nueva relación entre los participantes. Un ejemplo real de
transacción humana consiste en que un participante entrega dinero a cambio de un
producto, y a partir de ese momento el que da el dinero pasa a ser un cliente de quién le
vendió el producto. La implementación a nivel tecnológico de transacciones se lleva a
cabo mediante sistemas que manejan el estado de los participantes y que tienen un
sistema de almacenamiento persistente de cambios.

Las interacciones colaborativas tienen como principal utilidad que los participantes alteren
el estado de una entidad compartida (Puede considerarse como lo inverso de una
interacción mediante transacción). La entidad compartida tiene una forma relativamente
inestable. Un ejemplo es el desarrollo de una idea, la creación de un diseño o, en general,
la solución de un determinado objetivo compartido. Las tecnologías que deseen
implementar sistemas colaborativos deberán ofertar funcionalidad suficiente como para
que una serie de participantes puedan alcanzar un objetivo común. El manejo o
almacenamiento de documentos, hebras de discusión, o cualquier mecanismo que sea
capaz de capturar los esfuerzos comunes de una serie de usuarios dentro de un sistema
tecnológico debidamente gestionado son tecnologías típicamente asociadas a la
colaboración.

Proyecto Fin de Carrera | 2


1.1. Trabajo colaborativo asistido por ordenador

El término Trabajo colaborativo asistido por ordenador (en inglés Computer


Supported Cooperative Work (CSCW)) fue acuñado por Irene Greif y Paul M. Cashman
en 1984 [1]. Poco tiempo después, en 1987 Dr. Charles Findley presentó el concepto de
Trabajo Colaborativo. CSCW se refiere a "como actividades colaborativas y su
coordinación pueden ser soportadas por un sistema de computadoras". Muchos expertos
consideran que CSCW y groupware son sinónimos. Sin embargo, otros autores afirman
que mientras que el groupware hace referencia a los sistemas computacionales, CSCW
se enfoca en el estudio de herramientas y técnicas para groupware así como de sus
efectos psicológicos, sociales y organizativos. La siguiente definición expresa la diferencia
entre los dos conceptos:

"CSCW es un término genérico que combina el estudio de la forma en la que la


gente trabaja en grupo con la construcción de tecnologías que den soporte al
trabajo en grupo"

A lo largo de los años, diversos investigadores han identificado una serie de


características que debería tener cualquier sistema de éste tipo. Las principales son las
siguientes:

• Awareness. Los usuarios deben tener cierto grado de conocimiento acerca de las
actividades y estado del resto de usuarios.

• Trabajo articulado. Los usuarios que cooperan deben de ser capaces de participar
el trabajo en unidades más pequeñas, distribuir éstas particiones entre ellos y, una
vez terminado el trabajo, reintregrarlo todo de nuevo.

• Apropiación. La tecnología debe poder ser adaptada por un usuario o un grupo a su


situación particular o a su forma de trabajar, a pesar de que el diseño de ésta no

Proyecto Fin de Carrera | 3


contemplase ese uso inicialmente (Debe ser un sistema muy "abierto").

La complejidad en el desarrollo de un CSCW suficientemente genérico ha convertido el


último de los puntos anteriores en el más adecuado para que los investigadores en éste
tipo de sistemas empleen la mayor cantidad de esfuerzo. En general, los sistemas CSCW
que han resuelto con éxito algún tipo de problema de colaboración fallan a la hora de
adaptarlos a otros, a pesar de que sean parecidos entre sí. Es por esto último que el
desarrollo de un sistema genérico para la creación de sistemas de colaboración (una
plataforma), con alta capacidad de ampliación y adaptación al contexto en el que se use
es de especial interés.

Una de la formas más comunes de conceptualizar los sistemas CSCW es considerar sus
contextos de uso. La matriz CSCW, introducida por Johansen en 1988 [2], considera los
contextos de trabajo en dos dimensiones: La localización de los participantes y si éstos
actúan de forma síncrona o no. Una representación de ésta matriz se muestra a
continuación.

Ilustración 1: Asociaciones Tiempo/Lugar para Groupware

En concreto, en el caso de nuestro sistema nos centraremos en la parte inferior de las

Proyecto Fin de Carrera | 4


asociaciones Tiempo-Lugar, es decir, en las interacciones remotas y en la comunicación y
coordinación. A continuación se muestran las tecnologías asociadas a cada parte de la
matriz.

Mismo tiempo/Mismo lugar : Interacción cara a cara


• Roomware
• Mesas compartidas, pantallas murales
• Pizarras digitales
• Sistemas de soporte a la decisión de grupos (GDSS)
• Groupware en una sola pantalla

Mismo tiempo/Diferente lugar: Interacción remota


• Videoconferencia
• Groupware en tiempo real
• Mensajería (Mensajería instantánea, E-Mail)
• Editores multiusuario
• Pantallas compartidas (vnc)
• Mundos virtuales

Diferente tiempo/Mismo lugar: Tareas continuas


• Salas de grupo
• Pantallas gigantes públicas
• Post-it's

Diferente tiempo/Diferente lugar : Comunicación + Coordinación.


• Wiki's
• Blogs
• Control de flujo de trabajo
• Control de versiones

Proyecto Fin de Carrera | 5


1.2. Groupware

Groupware es la tecnología de computador para tratar los problemas del trabajo en


grupo. El término Groupware es una contracción de las palabras Group y Software. Este
término fue utilizado inicialmente para referirse a un sistema basado en computador más
los procesos sociales de grupos, sin embargo, fue restringido luego a sistemas basados
en computador. El propósito de groupware se puede resumir en asistir la colaboración,
comunicación y coordinación de las actividades de las personas que trabajan en grupo.
De aquí nace una de las definiciones más usadas de groupware, que lo define como:
“Sistema basado en computador que apoya a un grupo de personas dedicadas a una
tarea o meta común y que provee los servicios para apoyar la labor de los usuarios a
través de una interfaz de un ambiente compartido”. Las nociones de tarea común y
ambiente compartido son cruciales, ya que determinan la exclusión de sistemas que no
tienen tareas ni objetivos comunes, por ejemplo excluye a los sistemas multiusuarios de
tiempo compartido.

Los sistemas de groupware difieren de los tradicionales sistema de información, al permitir


que los usuarios interaccionen directamente entre ellos, ya sea preparando un
documento, consultando una base de datos o, incluso jugando, utilizando al computador
como herramienta de interacción, en vez de ser sistemas en los que el usuario interactúa
independientemente con el computador.

La comunicación que pueden obtener los grupos al utilizar aplicaciones Groupware, se


puede dividir en tres:

• Comunicación: El hecho en sí de comunicarse unos con otros.

• Coordinación: Es una actividad en sí misma, que ayuda a la organización de las


actividades de los miembros del grupo (por ejemplo, coordinar una tarea).

• Colaboración: Corresponde a la realización de actividades individuales, en forma


coordinada, que permiten la realización de una tarea en común (por ejemplo en los

Proyecto Fin de Carrera | 6


procesos de manufactura, donde distintas personas o maquinarias realizan ciertas
tareas, y al final, se juntan las partes para obtener el producto final).

Recapitulando, CSCW es un conjunto de aplicaciones groupware, orientadas en un


principio, al término trabajo. Sin embargo, el cambio fundamental es direccionar dichas
aplicaciones hacia actividades organizacionales. Para poder cambiar este esquema, se
debe tener en cuenta que se han detectado factores que influyen en el posible fracaso o
disminución sobre las expectativas, respecto de aplicaciones groupware.

Las aplicaciones groupware, a menudo fracasan porque requieren que parte del personal
realice su trabajo adicional, y esas personas no perciben un beneficio directo del uso de
aplicaciones. En este punto, es importante destacar que el nuevo objetivo de las
aplicaciones groupware, es modelar las actividades organizacionales, por tanto, se debe
establecer el margen adecuado para que todos los participantes se vean involucrados en
el proceso y puedan ser partícipes activos de él. Para esto se debe incorporar, en los
casos que sea necesario, equipos, instrucción y coordinación, para evitar quiebres que
dificulten el término de alguna tarea o proceso. Las aplicaciones groupware fallarán si no
permiten manejar el amplio rango de excepciones que caracterizan gran parte de la
actividad grupal.

Esta observación parece ser muy ambiciosa, ya que trata de abarcar todos los casos
posibles de excepciones. Sin embargo, en la actividad diaria, nuestro quehacer está
sometido a un constante cambio que no se puede prever del todo.

Proyecto Fin de Carrera | 7


1.3. Objetivos

El objetivo de este proyecto es el desarrollo de un Marco de trabajo (Framework) para el


soporte a la implementación de aplicaciones colaborativas.

Los principales hitos que se desean agregar al marco de trabajos son los siguientes:

• Plataforma de componentes gráficos replicados, con un estado global para todo


el sistema.

• Integración de todas las aplicaciones en un único sistema. Las aplicaciones se


comunicarán entre ellas, conformando un único sistema computacional de forma
transparente a los usuarios.

• Extensibilidad. Se trata de uno de los principales objetivos. Se trata de un objetivo


con doble vertiente:

• Por un lado, lo que se pretende es que el framework ofrezca la posibilidad de


construir sistemas fácilmente ampliable.

• Por el otro, se pretende que sea el propio framework el que sea extensible.
De esta forma, se podrá ampliar incluyendo nuevos componentes o
agregando nuevas funcionalidades.

• Portabilidad. Permitir la ejecución de aplicaciones en diversas plataformas


(Windows, Linux, Mac OS X, Solaris, etc.), con el objetivo de facilitar al máximo el
trabajo colaborativo, al no obligar a los usuarios a utilizar un determinado sistema.

Utilizando las características anteriormente enumeradas, se incorporarán al framework el


soporte necesario para proporcionar:

• Registro de usuarios y asignaciones de rol a éstos.

• Gestión de un conjunto de documentos (y directorios) compartidos. Los


usuarios del sistema puedan actuar con ellos como si estuviesen en su propio
equipo (borrar documentos, cambiarlos de ubicación, renombrarlos, cambiarles los

Proyecto Fin de Carrera | 8


permisos, ...). El sistema debe de soportar la aplicación de permisos de acceso
sobre los documentos. Así mismo, se pretende conseguir un primitivo control de
versiones.

• Anotación colaborativa de documentos de distintos formatos (imágenes, pdf,


etc.). Permitirá almacenar las anotaciones realizadas sobre el documento, así
como quién y cuándo las realizó.

• Comunicación entre los usuarios.

• Servicio de mensajería instantánea

• Servicio de e-mail

• Servicio de Videoconferencia

• Conciencia de grupo (awareness). Permite conocer en cada momentos qué


usuarios están conectados, bajo qué rol, qué documentos están siendo anotados
en este momento, etc.

Además de los objetivos arriba enumerados, también se persigue que el framework


desarrollado tenga, en la medida de lo posible, las siguientes características:

• Usabilidad. Como todo sistema informático que hace uso de interfaces de usuario,
la usabilidad (atributo de calidad que mide lo fáciles que son de usar las interfaces)
en nuestro sistema es clave. Para ello, se pondrá un especial empeño en que los
componentes desarrollados cumplan con una serie de requisitos con un grado de
usabilidad alto.

• Eficiencia. Toda la funcionalidad se implementará de forma local exceptuando al


gestión de eventos entre instancias que será distribuida. El funcionamiento de las
aplicaciones construidas con la API deben ser eficientes por el cometido que se
busca. Si no lo es, el usuario tendrá una realimentación muy pobre de sus acciones
lo que puede llegar a hacer que desista y termine por cerrar la aplicación. Por este
motivo se intentará hacer uso de una plataforma de gestión de la comunicación que
nos proporcione la eficiencia buscada.

• Fácil Desarrollo. Es necesario que el framework a desarrollar sea útil de cara a un

Proyecto Fin de Carrera | 9


futuro programador, a la vez que sencillo de ampliar. Debemos evitar el hecho de
que aprender a usar la funcionalidad ofertada exija más esfuerzo que los beneficios
que se van a obtener mediante su uso. Para garantizar que esto no suceda, se ha
intentado en todo momento que cada algoritmo, clase, componente, etc.
implementado sea absolutamente reutilizable, siga los estándares de desarrollo
más usados (incluido el formato a la hora de escribir el código y la codificación de
los ficheros que lo componen), sean de fácil uso y encapsulen en lo posible la
funcionalidad asociada a ellos, evitando en lo posible la cohesión entre unas
unidades de desarrollo y otras. No obstante, no todo se reduce al código, también
la documentación es esencial: para ello, no sólo se realizará una documentación
exhaustiva del código fuente, si no que también se explicará en detalle cada una de
las decisiones asumidas.

Proyecto Fin de Carrera | 10


2. Estado del arte

2.1. Metodología AMENITIES

AMENITIES [3] es una metodología basada en modelos de comportamiento y tareas para


el análisis, diseño y desarrollo de sistemas cooperativos.

La metodología parte de marcos teóricos cognitivos y metodológicos permitiendo realizar


un modelado conceptual del sistema cooperativo. Pretende abordar las carencias que
presentan los modelos para análisis y modelado de tareas ya que se centra en el
concepto de grupo, cubriendo aspectos relevantes de su comportamiento (dinámicas,
evolución, etc.) y estructura (organización, leyes, etc.). El objetivo de la metodología es
abordar de forma sistemática el análisis y diseño del sistema cooperativo facilitando el
desarrollo posterior del software.

AMENITIES proporciona un marco de referencia conceptual y metodológico, pero además


propone una metodología concreta. Esta metodología se ha aplicado a diversas áreas
como la gestión de recursos humanos en un sistema de control de emergencias o a la
representación de la colaboración para la gestión del conocimiento compartido.
En la siguiente figura se presenta el esquema general de la metodología AMENITIES. En
ella se muestran los principales modelos implicados y las fases generales. Estas fases
generales son las siguientes: (1) análisis del sistema y obtención de requisitos; (2)
modelado del sistema cooperativo; (3) análisis del modelo cooperativo; (4) diseño del
sistema, introduciendo nuevos elementos o cambios en el modelo cooperativo,
probablemente como resultado del análisis anterior; y (5) desarrollo del sistema software.

Ilustración 2: Modelo de la Metodología AMENITIES

Como en la mayoría de las metodologías, la aplicación de AMENITIES a un sistema sigue


un proceso iterativo simple, permitiendo llevar a cabo un refinado del modelo como
consecuencia del análisis de éste, así como una revisión de los requisitos de partida o del
modelo cooperativo que podría aportar nueva o diferente información a considerar.

2.2. Habanero

NCSA Habanero [4] es un framework y entorno colaborativo que contiene un conjunto de


aplicaciones.

Habanero permite la interacción entre personas a través de Internet usando distintas

Proyecto Fin de Carrera | 12


aplicaciones que comparten estado y eventos.

Habanero está escrito en Java. Esta plataforma o API está diseñada para dar a los
desarrolladores las herramientas necesarias para crear aplicaciones java colaborativas.

Usando el “Habanero Wizard”, los desarrolladores pueden fácilmente convertir applets por
medio de la selección de los objetos y eventos que quieren compartir. Entonces el
“Wizard” rescribe el código para beneficiarse de la API HABANERO.

Por otra parte, Habanero proporciona el entorno necesario para crear grupos de trabajo
colaborativos y comunidades virtuales.

Se compone de un servidor que almacena las sesiones y un cliente que interactúa con
sesiones haciendo uso de una variedad de aplicaciones llamadas Hablets. Las Sesiones
pueden grabarse persistentemente, accederse restringidamente e incluso pueden ser
anónimas.

El cliente de Habanero provee la interfaz para definir, listar, crear, unirse e interactuar con
una sesión:

" Información de sesión.


" Identificación de usuario.
" Mecanismo de notificación.
" Seguridad.
" Una lista de herramientas y usuarios activos.
" Un libro de direcciones, etc...

El cliente tiene 2 interfaces de usuario:

" Una se usa para predefinir sesiones en modo desconectado.


" Otra para interactuar con sesiones activas (conectado).

Proyecto Fin de Carrera | 13


2.3. La propuesta PageSpace

Los navegadores Web que soportan lenguajes de programación de Internet como Java
permiten actividad en la interfaz del usuario como puede ser los applets. Sin embargo
Java necesita ser integrado con middleware específico para coordinar actividades entre
múltiples clientes distribuidos. Una solución típica consiste en centralizar la coordinación
en algún servidor al que todos los usuarios participantes en una aplicación tienen que
conectarse. De eso modo, la comunicación no será directamente entre los participantes
pero ello no quita que siga siendo una aplicación distribuida.

El proyecto PageSpace propone una solución a este problema. De hecho PageSpace es


una arquitectura de coordinación capaz de soportar aplicaciones interactivas multiusuario
en el WWW. Introducimos una noción de espacio de coordinación para objetos activos
(los agentes) que son capaces de usar y proporcionar servicios desde y a otros agentes
sin requerir una coordinación centralizada.

El WWW es especialmente interesante para los usuarios porque ofrece un entorno


homogéneo en el cual pueden trabajar. Por el contrario las aplicaciones distribuidas
normalmente conllevan el uso de máquinas heterogéneas, redes y arquitecturas de
sistemas operativos. Para coordinar agentes en dicho entrono es necesario abstraer y
ocultar es heterogeneidad al programado. Para ello PageSpace está construido de una
serie de tecnologías:

" Tecnología web: Proporciona una amplia plataforma de presentación y


comunicación a PageSpace. Los navegadores permiten el acceso a PageSpace y
con HTML una interfaz homogénea para las aplicaciones.
" Tecnología Java: Proporciona una plataforma uniforme de procesamiento. Java es
famoso por su integración en los navegadores estándar y está disponible para la
mayoría de las plataformas existentes.
" Tecnología de coordinación: Lenguajes de alto nivel para programación distribuida
que ofrecen abstracciones útiles para construir aplicaciones seguras y eficientes.
Por ejemplo el lenguaje de coordinación Linda es muy conocido en el campo de la

Proyecto Fin de Carrera | 14


programación paralela. Sus abstracciones básicas pueden ser usadas para
programar arquitecturas distribuidas. De hecho el núcleo de PageSpace está
basado en Jada, una librería que mejora Java con la coordinación Linda.

En la propuesta PageSpace los usuarios emplean un navegador estándar para conectar a


un espacio compartido donde varios agentes de la aplicación están activos al mismo
tiempo realizando las tareas conectadas a sus roles. Para eliminar la naturaleza no
persistente, direccional y atómica de las conexiones HTTP, los navegadores no
interactúan directamente con el espacio compartido. Estos navegadores solo
proporcionan enlaces hacia applets Java.

Proyecto Fin de Carrera | 15


2.4. BSCW

Se trata de un entorno web basado en espacios compartidos de trabajo. Las siglas


corresponden a "Soporte básico para trabajo cooperativo". Comercial, con licencias
gratuitas para fines educativos y está traducido, entre otros idiomas, al castellano y al
catalán.

El sistema BSCW system nació en el Fraunhofer Institute for Applied Information


Technology FIT a mediados de los noventa. En 1998, un equipo desgajado del original,
OrbiTeam Software GmbH & Co. KG, asumió la responsabilidad del proceso del
desarrollo, marketing y soporte del sistema de espcio de trabajo compartido BSCW.

El sistema BSCW permite:


• Compartir documentos en internet.
# Guardar, compartir y administrar archivos (documents, pictures etc.).
# Acceso basado en password para amigos y compañeros.
• Organizar grupos de trabajo.
# Invitar a nuevos mienbros vía e-mail
# Crear un número arbitrario de grupos de trabajo.
# Usar versionado e informes de cambios para monitorizar procesos distribuidos.
# Permanecer informado de las actividades de los compañeros de equipo.
• Cooperar eficientemente.
# Crear blogs.
# Utilizar encuestas para recabar las opiniones de los compañeros de equipo.
# Gestionar citas contactos, tareas, contactos y notas.
# Envío automático de recordatorios de eventos y lista TODO.

Proyecto Fin de Carrera | 16


2.5. Google Docs and Spreadsheets

Es un programa gratuito basado en Web, para crear documentos en linea con la


posibilidad de colaborar en grupo. Incluye un procesador de textos, una hoja de cálculo y
un programa de presentación básico.

Se puede crear documentos desde la misma aplicación o Importarlos en los formatos


soportados, además de poder exportarlos en diversos formatos estándar o enviar por
email. Para evitar pérdida de información, Google Docs guarda automáticamente los
documentos abiertos. Otra característica importante es la posibilidad de Colaboración de
grupos de trabajo, además de poder compartirlos con múltiples usuarios al mismo tiempo.

Google Docs se originó de dos productos separados, Writely y Google Spreadsheets.


Writely era un procesador de texto individual en red, creado por la compañía de software
Upstartle, el cual fue lanzado en agosto de 2005[4]. Sus características originales incluían
un sitio para la edición de textos en colaboración, además de controles para su acceso.
Menus, atajos en el teclado y cuadros de diálogo presentados de una manera muy similar
a la que los usuarios suelen esperar en un procesador de texto tradicional, como
Microsoft Word o OpenOffice.org.

Proyecto Fin de Carrera | 17


2.6. MOODLE
Moodle es un sistema de gestión de recursos de libre distribución que ayuda a los
educadores a crear comunidades de aprendizaje en línea. Este tipo de plataformas
tecnológicas también se conocen como LMS (Learning Management System).

La primera versión de la herramienta apareció el 20 de agosto de 2002 y, a partir de allí


han aparecido nuevas versiones de forma regular. Hasta julio de 2008, la base de
usuarios registrados incluye más 21 millones, distribuidos en 46 000 sitios en todo el
mundo y está traducido a más de 70 idiomas.

Las opciones aportadas por MOODLE son:


! Asignación de tareas a los alumnos y establecimiento de un mecanismo de envío
de éstas.
! Notificaciones vía e-mail
! Gestión de un calendario
! Permite realizar encuestas y peticiones.
! Permite la inclusión de foros de discusión en la plataforma.
! Permite la definición de exámenes tipo test que serán calificados automáticamente.
! Permite que los profesores dejen ficheros para que los alumnos los descarguen.

Proyecto Fin de Carrera | 18


2.7. TOP: Una plataforma para el desarrollo de Interfaces y
Aplicaciones colaborativas sobre Web.

En este punto se describe una propuesta de plataforma basada en objetos para la


construcción de aplicaciones colaborativas sobre el Web. Se describe un esquema de
comunicación para que aplicaciones construidas sobre el Web puedan intercambiar
mensajes con un servidor de objetos. Este esquema provee una gran flexibilidad para la
construcción de interfaces Web y para el desarrollo de aplicaciones colaborativas en
Internet. La interfaz de estas aplicaciones fue construida sobre el Web utilizando el
esquema de comunicación propuesto.

Se va a intentar simplificar la creación de estas aplicaciones puesto que actualmente hay


muy pocas herramientas de desarrollo lo que implica comenzar desde labores de
comunicación de muy bajo nivel.

En esta plataforma el desarrollo de aplicaciones colaborativas se hace sobre el Web y


siguiendo un esquema de comunicación cliente-servidor, usando como clientes
documentos HTML con funciones JavaScript desde cualquier navegador que las soporte.

Proyecto Fin de Carrera | 19


3. Tecnologías

3.1. Swing
Java Además del paquete java.awt, pone a disposición del programador el paquete
javax.swing para el desarrollo de interfaces gráficas.

Swing ha sido totalmente escrito en Java utilizando el paquete awt, y pone a disposición
del usuario muchas clases que están también en awt, pero mucho mejores y más
potentes. Además introduce muchas más clases que no están en awt.

Los Componentes del interfaz gráfico son Beans y utilizan el modelo de Delegación de
Eventos de Java. Swing proporciona un conjunto completo de Componentes, todos ellos
lightweight, es decir, ya no se usan componentes "peer" dependientes del sistema
operativo, y además, Swing está totalmente escrito en Java. Todo ello redunda en una
mayor funcionalidad en manos del programador, y en la posibilidad de mejorar en gran
medida la cosmética de los interfaces gráficos de usuario.

Son muchas las ventajas que ofrece el uso de Swing. Por ejemplo, la navegación con el
teclado es automática, cualquier aplicación Swing se puede utilizar sin ratón, sin tener que
escribir ni una línea de código adicional. Las etiquetas de información, o "tool tips", se
pueden crear con una sola línea de código. Además, Swing aprovecha la circunstancia de
que sus Componentes no están renderizados sobre la pantalla por el sistema operativo
para soportar lo que llaman "pluggable look and feel" (del que hablaremos a
continuación), es decir, que la apariencia de la aplicación se adapta dinámicamente al
sistema operativo y plataforma en que esté corriendo.

3.2. Java look & feel

Cada ejecutable Java tiene un objeto UIManager que determina el Look-and-Feel, es


decir, la apariencia en pantalla y funcionamiento, que van a tener los Componentes Swing
de ese ejecutable. El Look-and-Feel es la apariencia que se proporciona a los diferentes
Componentes: botones, cajas de texto, cajas de selección, listas, etc.

Java utiliza el interfaz gráfico de la plataforma sobre la que se está ejecutando para
presentar los Componentes del AWT (o SWING) con el aspecto asociado a esa
plataforma, de este modo los programas que se ejecuten en Windows tendrán esa
apariencia y los que se ejecuten en Unix tendrán apariencia Motif. Pero Swing permite la
selección de esta apariencia gráfica, independientemente de la plataforma en que se esté
ejecutando; tanto es así que, la apariencia por defecto de los Componentes Swing se
denomina Metal, y es propia de Java. Teniendo siempre en cuenta las restricciones
impuestas por el control de seguridad, se puede seleccionar la apariencia, o Look-and-
Feel de los Componentes Swing invocando al método setLookAndFeel() del objeto
UIManager correspondiente al ejecutable. La forma en que se consigue esto es porque
cada objeto JComponent tiene un objeto ComponentUI correspondiente que realiza
todas las tareas de dibujo, manejo de eventos, control de tamaño, etc. para ese
Jcomponent.

Una de las ventajas que representan las capacidades de Look&Feel incorporadas a Swing
para las empresas, es el poder crear un interfaz gráfico estándar y corporativo. Con el
crecimiento de las intranets se están soportando muchas aplicaciones propias que deben
ejecutarse en varias plataformas, ya que lo más normal es que en una empresa haya
diferentes plataformas. Swing permite ahora que las aplicaciones propias diseñadas para
uso interno de la empresa tengan una apariencia exactamente igual, independientemente
de la plataforma en que se estén ejecutando.

Proyecto Fin de Carrera | 21


3.3. RMI

RMI (Java Remote Method Invocation) es un mecanismo ofrecido en Java para invocar
un método remotamente. Al ser RMI parte estándar del entorno de ejecución Java, usarlo
provee un mecanismo simple en una aplicación distribuida que solamente necesita
comunicar servidores codificados para Java. Si se requiere comunicarse con otras
tecnologías debe usarse CORBA o SOAP en lugar de RMI.

Al estar específicamente diseñado para Java, RMI puede darse el lujo de ser muy
amigable para los programadores, proveyendo paso de objetos por referencia (cosa que
no hace SOAP), "recolección de basura" distribuida y pasaje de tipos arbitrarios
(funcionalidad no provista por CORBA).

Por medio de RMI, un programa Java puede exportar un objeto. A partir de esa operación
este objeto está disponible en la red, esperando conexiones en un puerto TCP. Un cliente
puede entonces conectarse e invocar métodos. La invocación consiste en el "marshalling"
de los parámetros (utilizando la funcionalidad de "serialización" que provee Java), luego
se sigue con la invocación del método (cosa que sucede en el servidor). Mientras esto
sucede el llamador se queda esperando por una respuesta. Una vez que termina la
ejecución el valor de retorno (si lo hay) es serializado y enviado al cliente. El código
cliente recibe este valor como si la invocación hubiera sido local.

Ilustración 3: Implementación típica de una aplicación RMI. Desde Java 2 SDK, Standard Edition,
v1.2 no hay necesidad de Skeleton.

Arquitectura

La arquitectura RMI sigue un modelo por capas de acuerdo con el modelo de referencia
de Interconexión de Sistemas Abiertos (OSI, Open System Interconnection). Los

Proyecto Fin de Carrera | 22


protocolos utilizados en las tres capas superiores son propios de RMI; el resto de capas
utilizan protocolos genéricos (TCP, IP, etc.) [6].

Las capas propias de RMI serían:

1. La primera capa es la de aplicación y se corresponde con la implementación real


de las aplicaciones cliente servidor. Aquí tienen lugar las llamadas a alto nivel para
acceder y exportar objetos remotos. Cualquier aplicación que quiera que sus
métodos estén disponibles para su acceso por clientes remotos debe declarar
dichos métodos en una interfaz que extienda java.rmi.Remote. Dicha interfaz se
usa básicamente para "marcar" un objeto como remotamente accesible. Una vez
que los métodos han sido implementados, el objeto debe ser exportado. Esto
puede hacerse de forma implícita si el objeto extiende la clase
UnicastRemoteObject (paquete java.rmi.server), o puede hacerse de forma
explícita con una llamada al método exportObject() del mismo paquete.

2. La capa 2 es la capa proxy, capa de presentación, o capa stub-skeleton. Esta capa


es la que interacciona directamente con la capa de aplicación. Todas las llamadas
a objetos remotos y acciones junto con sus parámetros y retorno de objetos tienen
lugar en esta capa.

3. La capa 3 es la de referencia remota, y es responsable del manejo de la parte


semántica de las invocaciones remotas. También es responsable de la gestión de
la replicación de objetos y realización de tareas específicas de la implementación
con los objetos remotos, como el establecimiento de las persistencias semánticas y
estrategias adecuadas para la recuperación de conexiones perdidas. En esta capa
se espera una conexión de tipo stream (stream-oriented connection) desde la capa
de transporte. El protocolo utilizado RMI Transport Protocol (ver [7]), que
solamente es "comprendido" por programas Java.

Proyecto Fin de Carrera | 23


CLIENTE OBJETO REMOTO OSI
Cliente invocando método Objeto ofreciendo servicio Capa de aplicación
remoto
Stub Skeleton Capa de presentación
RMI Transport Protocol RMI Transport Protocol Capa de sesión

TCP TCP Capa de transporte


IP IP Capa de red
Interfaz Hardware Interfaz Hardware Capa de enlace
Tabla 3.1.: Arquitectura en capas de RMI

Elementos
Toda aplicación RMI normalmente se descompone en 2 partes:

• Un servidor, que crea algunos objetos remotos, crea referencias para hacerlos
accesibles, y espera a que el cliente los invoque.

• Un cliente, que obtiene una referencia a objetos remotos en el servidor, y los


invoca.

Proyecto Fin de Carrera | 24


3.4. JINI

Sun Microsystems introduce Jini, basado en tecnología Java, en 1998. El corazón de Jini
es un trío de protocolos: discovery, join y lookup. Un par de estos protocolos, discovery y
join, ocurren cuando se conecta un dispositivo a la red; discovery ocurre cuando un
servicio busca un servicio lookup con quien pueda registrase, y join ocurre cuando un
servicio localiza un servicio lookup y desea suscribirse a este. Lookup ocurre cuando un
cliente o usuario localiza e invoca un servicio descrito por su tipo de interfaz (escrita en el
lenguaje de programación Java) y posiblemente otros atributos. Para que un cliente en
una comunidad Jini use un servicio:

El proveedor de servicio debe localizar un servicio lookup por una petición multicast en la
red local o por conocimiento a priori de un servicio lookup remoto.

El proveedor de servicio debe registrar un objeto servicio y sus atributos en un servicio


lookup. Este objeto servicio contiene una interfaz Java
para el servicio, que incluye los métodos que usuarios y
aplicaciones invocarán para ejecutar el servicio (Ver figura
3.1a).
El cliente entonces solicita un servicio por el tipo y quizás
por atributos. El servidor lookup envía una copia del objeto
servicio a través de la red al cliente, quien usa este para
conversar con el servicio.

El cliente interactúa directamente con el servicio vía el


objeto servicio.

La tecnología Jini se compone de una infraestructura y un


modelo de programación que determina como dispositivos
Ilustración 4: Capas en Jini se conectan con otros para formar una improvisada
comunidad. Jini usa el método de invocación remota de

Proyecto Fin de Carrera | 25


Java (RMI) para mover código por la red.

Se puede visualizar el servicio Jini lookup como un servicio de directorio. Jini usa tres
protocolos de descubrimiento relacionados. Cuando una aplicación o servicio es recién
activada, el protocolo de petición multicast busca un servicio lookup en la vecindad. Los
servicios lookup utilizan el protocolo de anuncio multicast para anunciar su presencia a
servicios en la comunidad que pudieran estar interesados. El protocolo de descubrimiento
unicast entonces establece comunicación con un específico servicio lookup ya conocido.

Sin embargo, un servicio Jini lookup no es solamente un servidor de nombres. Este traza
las interfaces con que los clientes ven a los objetos proxy servicio. Este también mantiene
atributos de servicio y procesa consultas. Los clientes descargan el proxy servicio que es
usualmente un stub RMI que puede comunicarse con el servidor. Este proxy objeto
permite a clientes usar el servicio sin saber nada acerca de este. Aquí, no son necesarios
los drivers en caso de que el servicio proveído sea un periférico (por ejemplo impresora).
El objeto servicio descargado puede ser el servicio mismo o un objeto inteligente capaz de
conversar en un protocolo de comunicación privado.

Arrendamiento en Jini

Jini concede acceso a sus servicios en base al arrendamiento. Un cliente pude solicitar un
servicio por un determinado periodo de tiempo, y Jini dará un arriendo negociado por ese
periodo. Este arriendo debe ser renovado antes que este expire; sino Jini liberá los
recursos asociados con el servicio. El arrendamiento permite a Jini ser robusto cuando se
enfrenta a fallas abruptas o desconexión de dispositivos y servicios.

Programación distribuida en Jini

Además del servicio básico de descubrimiento y mecanismos join y lookup, Jini soporta
eventos remotos y transacciones que ayudan a programadores a escribir programas
distribuidos en una forma fiable y escalable. Los eventos remotos notifican un objeto
cuando un cambio deseado ocurre en el sistema. Nuevos servicios publicados o algunos

Proyecto Fin de Carrera | 26


cambios de estado en servicios registrados pueden activar estos eventos. Por ejemplo, el
servicio lookup puede notificar a una PDA Jini, que tiene registrado su interés en
impresoras, cuando una de ellas esté disponible. También, Jini soporta la noción de
transacciones y compromiso atómico de ellas.

Universal Plug and Play

UpnP es una evolución del estándar inicial de Microsoft que extiende el modelo de
periféricos Plug-and-Play. Esto apunta a permitir el anuncio, descubrimiento y control de
dispositivos en red, servicios y electrodomésticos. En UPnP, un dispositivo puede
dinámicamente unirse a una red, obtener una dirección IP, transmitir sus capacidades por
demanda, y conocer la presencia y capacidades de otros dispositivos. Un dispositivo
también puede abandonar una red fácilmente, y automáticamente abandonar el estado de
disponibilidad anterior. UpnP está influenciado por TCP/IP y tecnologías Web, incluyendo
IP, TCP, UDP, HTTP, y XML.

Suscripción y descubrimiento en UpnP

UpnP usa Simple Service Discovery Protocol (SSDP) para el descubrimiento de servicios.
Este protocolo anuncia la presencia de un dispositivo a otros y descubre otros dispositivos
o servicios. Por consiguiente, SSDP es análogo al trío de protocolos en Jini. SSDP usa
http sobre multicast y unicast UDP, conocidos como HTTPMU y HTTPU, respectivamente.
Un dispositivo acoplado envía un mensaje de anuncio (ssdp:alive) multicast para anunciar
sus servicios a puntos de control. Los puntos de control funcionan de forma similar que los
servicios lookup de Jini. Un punto de control, si está presente, puede guardar el anuncio,
u otros dispositivos pueden también ver directamente este mensaje multicast. UpnP
puede trabajar con o sin los puntos de control (servicio lookup). Este envía un mensaje
multicast de búsqueda (ssdp:discover) cuando un nuevo punto de control es agregado a
la red. Cualquier dispositivo que escuche este multicast responderá con un mensaje
unicast de respuesta.

UPnP usa XML para describir las capacidades y características de los dispositivos. El

Proyecto Fin de Carrera | 27


mencionado mensaje de anuncio contiene una URL que apunta a un archivo XML en la
red que describe las capacidades del dispositivo. Recuperado este archivo XML, otros
dispositivos pueden inspeccionar la información de las características del dispositivo y
decidir si es importante o relevante para ellos. XML permite una compleja y poderosa
descripción de dispositivos y capacidades de servicios a diferencia de una simple
descripción de atributos en Jini.

Descripción de servicio UPnP

Luego de que un punto de control descubre un dispositivo, este aprende mas acerca de
cómo usarlo, controlarlo, coordinarse con él por medio de la descripción del archivo XML.
El control es expresado como una colección de objetos de Simple Object Access Protocol
(SOAP) y sus URLs en el archivo XML. Para usar un control específico, un mensaje
SOAP es enviado a un objeto de control SOAP a la URL específica. El dispositivo o
servicio retorna valores específicos de la acción.

Una descripción UPnP para un servicio incluye una lista de acciones a las que el servicio
responderá y una lista de variables que muestran el estado del servicio en tiempo de
ejecución. El servicios publica actualizaciones cuando estas variables cambian, un punto
de control puede suscribirse para recibir esta información. Las actualizaciones son
publicadas enviando mensajes de evento que contienen los nombres y valores de una o
mas variables de estado. Estos mensajes también son expresados en XML y formateados
usando la Arquitectura General de Notificación de Eventos.

UPnP ofrece agregar una descripción de alto nivel de servicios en la forma de una interfaz
de usuario. Esta característica permite que los usuarios controlen directamente el servicio.
Si un dispositivo o servicio tiene una URL de presentación, entonces el punto de control
puede recuperar una página desde esta URL, cargar la página en un navegador web y
(dependiendo de las capacidades de la página) permite al usuario controlar el dispositivo
o ver el estado de él.

Proyecto Fin de Carrera | 28


Configuración automática de IP

Otra importante característica de UPnP es la configuración automática de direcciones IP.


AutoIP permite a un dispositivo unirse a la red sin una administración explícita. Cuando un
dispositivo se conecta a la red, intenta adquirir una dirección IP desde un servidor
Dynamic Host Configuration Protocol (DHCP). Sin embargo, en la ausencia de un servidor
DHCP, es reclamada automáticamente una dirección IP desde un rango de direcciones
reservadas de la red local en uso. El dispositivo pide una dirección aleatoriamente elegida
y hace una petición ARP para comprobar si alguien más reclama la dirección.

Proyecto Fin de Carrera | 29


3.5. JavaSpaces

JavaSpaces es la plataforma que se va a usar en el proyecto que se está desarrollando


para las labores de comunicación. Es una implementación del modelo de coordinación
LINDA basada en JINI haciendo uso de los servicios y beneficios que proporciona.

Revisión del Paradigma de Espacio de Tuplas

Introducción
El propósito de la computación distribuida es diseñar y construir aplicaciones como un
conjunto de procesos que son distribuidos sobre una red de computadores y trabajar
juntos como una unidad. Esto produce una mayor escalabilidad y fiabilidad en los
sistemas. Estos sistemas son difíciles de construir ya que al existir más de un computador
se requiere de la coordinación entre ellos, tarea nada sencilla.

Un amplio rango de paradigmas de programación han evolucionado para escribir software


para arquitecturas paralelas y distribuidas. Todos éstos usan alguna forma de
“middleware”.

Memoria compartida distribuida (DSM)


Abstracción para compartir datos entre computadores que no comparten memoria física.
Los procesos acceden a ella con lecturas y escrituras normales; mientras una capa
inferior propaga transparentemente a lo largo de los nodos de la red esos accesos.

Aproximaciones:

• Basada en páginas.
• Basada en variables compartidas.
• Basada en Objetos (espacios de tuplas): los procesos en múltiples máquinas
comparten un espacio abstracto que contiene los objetos compartidos.

Proyecto Fin de Carrera | 30


El paradigma de espacio de tuplas ha ido ganando adeptos en aquellas categorías de
aplicaciones comerciales donde el intercambio de objetos y coordinación en un entorno
distribuido, son importantes.

Espacios de tuplas
Un espacio de tuplas es una implementación del paradigma de la memoria asociativa para
la computación paralela/distribuida. Un espacio es un repositorio compartido a través de
red para objetos o tuplas. Como un espacio de tuplas es global a todo el sistema, los
procesos en cualquier máquina pueden insertar tuplas o quitarlas concurrentemente. Una
tupla es una estructura de datos con varios campos tipados con algún valor.

Operaciones
Se definen sólo unas pocas operaciones atómicas.
Operación Descripción
Out Inserta una tupla dentro del espacio
In Saca una tupla del espacio
Rd Inspecciona (lee) una tupla en el espacio
sin quitarla.
Tabla 3.2: Operaciones básias en un espacio de tuplas

Las dos últimas operaciones de la tabla usan una plantilla (template) para buscar en un
espacio. Cuando múltiples tuplas emparejan con una plantilla de búsqueda, una tupla
arbitrariamente es devuelta.

Programación basada en espacio


Las habilidades proporcionadas por un espacio son la compartición de datos y
coordinación de eventos de los procesos en un entorno distribuido.

La principal ventaja es el desacoplamiento temporal y espacial inherente a este


paradigma; ya que las tuplas y el espacio pueden persistir tras la finalización de aquel
proceso que las introdujo en él.

Proyecto Fin de Carrera | 31


Algunas implementaciones
El concepto de “espacio de tuplas” fue introducido por el prototipo Linda. Linda se
implementa como una extensión de un lenguaje existente (por ejemplo C) incorporándole
primitivas extra para las operaciones del espacio de tuplas.

Los programas escritos en Linda son procesados por un precompilador que transforma el
programa en un lenguaje de programación nativo. Después, ese programa se puede
compilar con el compilador normal para ese lenguaje. Linda añade predicados variantes
de las operaciones in y rd llamados inp y rdp que son no-bloqueantes. Si ninguna tupla
empareja, se devuelve false.

JavaSpaces (Sun) y TSpaces (IBM) son implementaciones de espacios de tuplas


orientados a objetos, inspirados en Linda. TSpaces es un sistema híbrido que está entre
un espacio de tuplas puro y una base de datos relacional. El servidor se compone de 2
capas. A diferencia de JavaSpaces, no requiere APIs clientes/servidoras basadas en
Java, ni RMI.

Espacio de tuplas distribuido


La mayoría de los espacios de tuplas implementados hasta el momento (incluyendo el
original Linda y la implementación de referencia de JavaSpaces, proporcionada por Sun),
son sistemas centralizados. De esta forma, están expuestos a los problemas clásicos de
los sistemas centralizados:

• Único punto de fallo. Las tuplas están almacenadas sólo en un lugar de modo que
si el computador falla, todas se pierden.
• Cuello de botella.

Un espacio de tuplas distribuido es una abstracción que presenta varios espacios,


ejecutándose en nodos de red separados, como uno sólo. Con esto se mejora la
disponibilidad y escalabilidad en términos de prestaciones, comparado a las
implementaciones puramente centralizadas.

Proyecto Fin de Carrera | 32


Normalmente se usan dos técnicas comúnmente empleadas en sistemas distribuidos en
general:

• Replicación. Mitiga los problemas de tolerancia a fallos. Se basa en mantener


múltiples copias de algunos datos (replicas), dando la impresión de ser una unidad.
La dificultad principal es mantener la coherencia entre las replicas para asegurar la
semántica del sistema.

• Particionamiento. Mejora la escalabilidad dividiendo el espacio distribuido en


varias particiones de espacio de tuplas disjuntas. Cada partición contiene un
subconjunto de tuplas. Plantea la necesidad del “balanceo de carga”.

Resumen de la especificación de JavaSpaces


Introducción
Esta especificación describe la arquitectura de la tecnología JavaSpaces que está
diseñada para ayudar a resolver 2 problemas relacionados:

! Persistencia distribuida.
! Diseño de algoritmos distribuidos.

Los servicios de JavaSpaces usan RMI y las características de serialización de Java para
alcanzar esas metas.

Terminos y modelo de aplicación


Un servicio de JavaSpaces mantiene entradas (entries): grupo de objetos con tipo. Éstas
pueden ser escritas dentro de un servicio JS, el cual crea una copia que posteriormente
podrá ser buscada (operaciones de lookup).

La búsqueda de entradas se hace mediante plantillas (templates). Existen 2 operaciones


de búsqueda: read y take.

Se puede mostrar interés en un tipo de entradas según una plantilla, de forma que el

Proyecto Fin de Carrera | 33


servicio nos notifique (notify) cuando una entrada con esas características es escrita.

Persistencia distribuida
Las implementaciones de la tecnología JavaSpaces proveen un mecanismo para
almacenar un grupo de objetos relacionados y recuperarlos según un patrón de búsqueda
especificado por los campos de una plantilla. Esto permite a un servicio de JavaSpaces
ser usado para almacenar y recuperar objetos en un sistema remoto.

Algoritmos distribuidos como flujo de objetos


Muchos algoritmos distribuidos pueden modelarse como un flujo de objetos entre
participantes.

En general, una aplicación JavaSpaces siguen la siguiente estructura:

Ilustración 5: Arquitectura de una aplicación que usa


JavaSpaces

Beneficios

Los servicios JavaSpaces son herramientas para construir protocolos distribuidos, pueden
proveer un sistema de almacenamiento distribuido fiable para objetos y persistencia de
objetos distribuidos facilitando la computación cooperativa.

Proyecto Fin de Carrera | 34


Tecnología JavaSpaces y las Bases de datos
Aunque pueda almacenar persistentemente datos accesibles con posterioridad, un
servicio JavaSpaces no es ni una Base de datos Relacional ni OO.

Diferencias importantes por los distintos propósitos de estos sistemas:

• No hay consultas genéricas en JavaSpaces sino sólo “emparejamientos exactos” o


no, dado un campo. Una característica notable de las BDRs es su capacidad de
comprender los datos que almacenan y manipularlos a través de lenguajes de
consulta.

• Mientras que una BDOO provee una imagen OO de los datos que almacena, los
sistemas JavaSpaces no lo hacen, funcionando estos últimos simplemente como
copias de entradas.

Objetivos y requerimientos
Los objetivos de esta tecnología son:

• Proporcionar una plataforma para el diseño de sistemas de computación distribuida


que simplifique su construcción.
• El cliente debe tener pocas clases y ocupar poco.
• Debe ser posible crear servicio de JavaSpaces replicados.
• Debe ser posible escribir clientes puramente en java.

Operaciones
Existen cuatro tipos de operaciones principales que podemos invocar sobre un servicio de
JavaSpaces: write, read, take, notify.

Entradas
Objetos de la clase Entry, que se almacenan en el espacio para (mediante su intercambio)

Proyecto Fin de Carrera | 35


implementar los algoritmos distribuidos basados en flujo de objetos.
Write
Introduce una copia de una entrada en un servicio JavaSpaces dado. Cada entrada que
se “escribe” en el espacio será independiente de la anterior, aun siendo el mismo objeto el
que estemos utilizando.

ReadIfExists y Read
Ambas formas buscan en un servicio JavaSpaces (espacio) una entrada que empareje
con la plantilla pasada. Si hay un emparejamiento, una copia local es creada, de lo
contrario, se devuelve NULL. Los valores nulos (NULL) en las plantillas suponen el
emparejamiento con cualquier valor en las entradas.

Una característica importante es que sucesivas ejecuciones de estas operaciones no


aseguran encontrar los siguientes objetos emparejados, pudiendo recibir los encontrados
en las anteriores veces.

La diferencia entre ReadIfExits y Read es que la primera retorna inmediatamente con un


emparejamiento o null, mientras que la segunda se queda bloqueada en espera de un
emparejamiento mientras no expire el tiempo máximo de espera asociado.

TakeIfExists y Take
Son esencialmente idénticas a las anteriores con la salvedad de retirar (eliminar) del
espacio el objeto que empareje.

Notify (notificación)
Una petición de este tipo registra el interés en la llegada posterior de entradas al espacio
con características que emparejen con una plantilla determinada.

Todo el mecanismo que envuelve a esta operación se denominada en JINI, “Eventos


Distribuidos”.

Proyecto Fin de Carrera | 36


Cuando se escriben entradas que hacen lanzar el servicio de notificación un objeto del
tipo RemoteEventListener será notificado. Este objeto se debió registrar en la operación
de Notify original en la que se especificó el patrón de emparejamiento por el que debería
“avisarse” a ese objeto.

Ordenamiento
Las operaciones sobre un espacio carecen de orden; preservándose sí la atomicidad de
las mismas a la hora de ver los cambios por otras operaciones concurrentes.

Transacciones
La API de JavaSpaces usa el paquete net.jini.core.transaction para proporcionar
transacciones atómicas básicas que agrupen múltiples operaciones a través de múltiples
espacios actuando como una única operación atómica.

Operaciones bajo transacciones


Cualquier operación que no tenga transacción actúa como si se hiciese un “commit” tras
su ejecución.

En el caso de empaquetarse dentro de una transacción se modifica su comportamiento en


el siguiente modo:

! Write. Una entrada escrita no es visible fuera de su transacción hasta que se


proceda al “commit”.

! Read/Take(ifExists). Es capaz de emparejar tanto con entradas en el espacio


actual como con entradas escritas a lo largo de su transacción.

! Notify. Notifica adicionalmente las escrituras hechas dentro de su transacción.

Proyecto Fin de Carrera | 37


3.6. MySQL

MySQL es un sistema de gestión de base de datos relacional, multihilo y multiusuario.

Inicialmente, MySQL carecía de elementos considerados esenciales en las bases de


datos relacionales, tales como integridad referencial y transacciones. A pesar de ello,
atrajo a los desarrolladores de páginas web con contenido dinámico, justamente por su
simplicidad.

Poco a poco los elementos de los que carecía MySQL están siendo incorporados tanto
por desarrollos internos, como por desarrolladores de software libre. Entre las
características disponibles en las últimas versiones se puede destacar:

• Amplio subconjunto del lenguaje SQL. Algunas extensiones son incluidas


igualmente.

• Disponibilidad en gran cantidad de plataformas y sistemas.

• Diferentes opciones de almacenamiento según si se desea velocidad en las


operaciones o el mayor número de operaciones disponibles.

• Transacciones y claves externas.

• Conectividad segura.

• Replicación.

• Búsqueda e indexación de campos de texto.

Proyecto Fin de Carrera | 38


3.7. PDFRenderer

En 2003, investigadores de Sun Labs desarrollaron el PDF Renderer como parte de una
herramienta de audio colaborativo (Sun(TM) Labs Meeting Suite), que es usada de forma
intensiva en las reuniones distribuidas en Sun. Meeting Suite fue desarrollada para
realizar presentaciones creadas con OpenOffice.

PDF Renderer es justo lo que su nombre indica: una librería open source escrita en java
que permite renderizar documentos PDF en la pantalla utilizando Java2D. Típicamente
esto significa dibujar en un JPanel de la biblioteca Swing, pero también puede dibujarse
en otras implementaciones de Graphics2D.

Es importante destacar que PDFRender no genera documentos PDF, sino que permite
visualizarlos.

Proyecto Fin de Carrera | 39


4. Especificación y Análisis de Requisitos

4.1. Descripción del sistema

El framework a implementar, está orientado a dar soporte al desarrollo de sistemas con


las siguientes características:

El sistema contará con un conjunto de aplicaciones clientes que se comunicarán a través


de la red con una serie de aplicaciones (servidores) que proporcionan a éstas una serie
de servicios (acceso a la metainformación de los usuarios, acceso a los documentos
compartidos, etc. ).

Por cada aplicación cliente se tienen:

1. Conjunto de usuarios que pueden acceder a ella.

2. Conjunto de roles que pueden acceder a una aplicación.

3. Conjunto de componentes con los que un usuario (bajo un determinado rol)


puede actuar.

Las relaciones que se establecen entre los elementos anteriores son la siguientes:

1. Un determinado usuario puede desempeñar más de un rol en el sistema, pero


sólo puede se desempeñar un único rol en un momento dado.

2. Se pueden especificar restricciones de acceso a un determinado componente


para un determinado usuario con un esquema: escritura/lectura (el usuario
puede ver el componente e interaccionar con él), sólo lectura (el usuario sólo
podrá ver el componente) y acceso prohibido (el componente se esconde).

3. El mismo comportamiento del punto anterior de los usuarios con respecto a los
componentes se da para los roles.

4. Para determinar los permisos de un usuario en un momento determinado,


siempre será el nivel menos restrictivo de los especificados a nivel de usuario y
a nivel de rol.

5. El sistema se encargará de gestionar una serie de documentos en formato


electrónico (imágenes, PDF, documentos de texto, etc. ) que serán vistos por
parte de los usuarios de las aplicaciones cliente como una serie de recursos
compartidos a los que pueden acceder como si fuesen recursos locales. Los
documentos serán almacenados de manera que al usuario se le presenten de la
forma en la que está acostumbrado, es decir, en forma de un árbol de
directorios.

Al igual que con los componentes cada fichero tiene asociados unos permisos, que
determinan qué usuarios y/o roles pueden leer/escribir el documento en cuestión.

Así mismo, cada aplicación constará de una serie de plugin, o mini-aplicaciones, que
extenderán la funcionalidad de la aplicación (chat, videoconferencia, pizarra compartida,
cálculo distribuido, etc.). Los plugins podrán ser añadidos, eliminados, desactivados, etc.
por parte del usuario de las aplicaciones cliente. Además, los plugin dispondrán de un
mecanismo de versionado, que permitirá que el sistema distribuya de forma automática
las nuevas versiones de los plugins, dando siempre al usuario la opción de actualizarla el
plugin o no.

Proyecto Fin de Carrera | 41


4.2. Requisitos funcionales

Desarrollo de un framework para la construcción, de forma rápida y sencilla, de


aplicaciones colaborativas en Java utilizando componentes replicados. Dicha replicación
consistirá en que varios usuarios estarán interaccionando con el componente de forma
simultánea manteniendo un estado consistente global. Se abstraerán todos los detalles
de más bajo nivel para conseguir los objetivos reseñados de sencillez y rapidez de
desarrollo.

Así mismo, el framework permitirá la modificación dinámica de la metainformación de


usuarios, roles, componentes y ficheros, distribuyendo estos cambios por el sistema y
almacenándolos de forma permanente.

Por otro lado, el framework también ofrecerá la posibilidad de desarrollar plugins para las
aplicaciones y gestionar su versionado de forma fácil y simple; más aún, el framework
proporcionará mecanismos de gestión de los plugins, de manera que éstos puedan ser
cargados en el sistema, activados, modificados, etc. Con el uso de los plugins se
conseguirá el objetivo de construir un framework para dar soporte a la implementación de
aplicaciones extensibles.

Finalmente, el framework también se encargará de proporcionar facilidades para la


gestión de los ficheros compartidos, ofreciendo mecanismos de visualización de
documentos, almacenamiento remoto y local, distribución de modificaciones en los
documentos a todos los clientes del sistema, soporte a la anotación colaborativa de
documentos, etc.

Programación de una aplicación de ejemplo y de un conjunto de plugins que muestren


todas las funcionalidades del framework desarrollado. Así mismo, se distribuirán una serie
de manuales del desarrollador que intentarán facilitar la tarea del desarrollo utilizando el
framework.

Proyecto Fin de Carrera | 42


4.3. Requisitos No Funcionales

A continuación se listan los requerimientos no funcionales hallados para el sistema a


desarrollar:

1. Requisitos de Calidad

a. Facilidad de Uso: Dado que el sistema a desarrollar está orientado a ser


utilizado por usuarios con cualquier nivel de conocimientos informáticos, la
facilidad de uso del sistema debe ser un punto clave a la hora de diseñar el
sistema. Ésto tendrá que tenerse especialmente en cuenta a la hora de
diseñar el interfaz gráfico de la aplicación.

b. Fiabilidad: Fiabilidad desplazada a los servidores de información. Se


presupone la fiabilidad de los servicios externos sobre los que se
implemente el sistema. Los controles de fiabilidad, por tanto, solo serán
considerados en las entidades de alto nivel implementados. Se emplearán
pequeños mecanismos que eviten los fallos más comunes en los sistemas
de más bajo nivel de los que se hace uso (pequeños cortes de la conexión
de red, por ejemplo).

c. Rendimiento: Importante, pero no determinante. Se intentará que el sistema


del usuario no se vea afectado demasiado por el uso prolongado de la
aplicación. Se evitarán tareas de alto coste computacional siempre que sea
posible, y cuando sean estrictamente necesarias, se intentará situar éstas en
hebras distintas a la hebra principal, de tal manera que la aplicación tenga
un buen tiempo de respuesta durante la interacción del usuario con ésta. Se
evitará todo el procesamiento que sea posible en los servidores. Se evitará
que se sobrecarguen los servidores con información masiva (Por ejemplo,
con transmisiones de ficheros).

Proyecto Fin de Carrera | 43


d. Soporte: Se permitirá la adaptación total del sistema gracias al uso de
plugins, que no solo serán aplicaciones al uso, si no también ampliaciones
del sistema propiamente dicho, tales como nuevos filtros para soporte de
documentos. Se permitirá la internacionalización de la aplicación, aunque
esto no tendrá una especial relevancia. En cuanto a configurabilidad, no se
permitirán los cambios en la interfaz gráfica sin modificar el código fuente.
Se podrá configurar desde el cliente la metainformación del sistema, así
como la dirección de red de los servidores (no se deberá cambiar el código
fuente de la aplicación si la ubicación de los servidores en la red cambia).

2. Pseudo-Requisitos

a. Implementación: Java 1.5. No deberá haber ningún tipo de restricción en


cuanto al hardware, excepto que debe tener soporte para la conexión en red
y debe estar soportado por Java 1.5, obviamente. Para el desarrollo de
plugins o de futuras versiones de la aplicación no se requerirá ningún tipo de
herramienta o IDE específicos, aunque se recomendará el uso de IDE's que
tengan soporte para herramientas de control de versiones como SVN y que
sean de amplio uso. Especialmente se recomiendan Eclipse y Netbeans.

b. Interfaz: Se usarán bibliotecas que permitan el acceso al hardware de


captura de audio y video desde una aplicación Java. También se usarán
bibliotecas que den soporte a formatos de fichero tales como PDF. Se usará
JINI, RMI y JavaSpaces como interfaz entre la red de bajo nivel y la
aplicación de alto nivel.

c. Operación: Servidores a cargo de personal especializado. La aplicación


cliente podrá ser operada por un usuario con conocimientos mínimos en
informática.

d. Empaquetamiento: Distribución multiplataforma mediante scripts de

Proyecto Fin de Carrera | 44


consola para Windows y Linux. Para Mac OS X se dan ejecutables. Se dan
instaladores para todas las plataformas, con alto nivel de integración para
cada una de ellas (especialmente para Windows y Mac OS X). El software
requerido por los servidores (Java, MySQL y servicios de JINI) y por los
clientes (Java) se proporcionará también junto a la aplicación final. El código
fuente se distribuirá junto a los ejecutables finales y, mediante el sistema de
control de versiones SVN a través del comando de consola:

svn checkout http://jdistlib.googlecode.com/svn/trunk/ jdistlib-read-only

Se puede obtener el equivalente a éste comando haciendo uso de IDE's o de


aplicaciones con GUI para la gestión de un servidor SVN (como
"TortoiseSVN").

e. Legales: Licencia LGPL para el código fuente. Licencias OpenSource


((L)GPL y Apache) para todas las bibliotecas y herramientas usadas.

Proyecto Fin de Carrera | 45


4.4. Análisis de los requerimientos para el sistema

En este apartado, vamos a dedicarnos al análisis de los requisitos propios de


los sistemas a desarrollar con nuestro framework. Para ello, utilizaremos
como herramienta de modelado los casos de uso, propios del lenguaje de
modelado UML. Finalmente, se extraerán las operaciones del sistema, que
son los servicios o funciones principales que ofrece el sistema y permiten
describir el comportamiento de un sistema centrándose en el qué y obviando
el cómo.

4.4.1. Lista de Casos de Uso

En las aplicaciones ha desarrollar haciendo uso de el framework, se han identificado los


siguientes roles:

! Usuario: identifica a un usuario típico de la aplicación.

! Administrador: especialización de Usuario, tiene privilegios para editar la


metainformación del sistema

En la Tabla 4.1: Resumen de los casos de uso se listan los casos de uso hallados para la
aplicación típica que se desarrollará con nuestro Framework.

Proyecto Fin de Carrera | 46


Actor Primario Caso de Uso Descripción

Usuario Abrir Documento El usuario abre un documento para


realizar la anotación compartida de un
documento

Usuario Anotar Documento El usuario realiza una anotación sobre


el documento abierto

Usuario Imprimir Documento El usuario imprime un documento

Usuario Guardar Documento El usuario guarda un documento junto


con los cambios realizados en las
anotaciones

Usuario Eliminar Anotación El usuario elimina una anotación


realizada en el documento

Usuario Subir Documento El usuario sube un documento al


servidor

Usuario Descargar Documento El usuario descarga un documento del


servidor

Usuario Agregar Carpeta El usuario agrega una nueva carpeta


en el servidor

Usuario Eliminar Documento El usuario elimina un documento del


servidor

Usuario Mover Documento El usuario mueve un documento de una


carpeta a otra

Usuario Ver Propiedades El usuario accede a las propiedades de


Documento un documento y puede modificar

Proyecto Fin de Carrera | 47


algunas de ellas

Usuario Chatear El usuario accede al chat del sistema

Usuario Establecer Conversación El usuario establece una conversación


Privada privada con otro usuario del sistema

Usuario Realizar Videoconferencia El usuario establece una


videoconferencia con privada con otro
usuario del sistema

Usuario Cambiar Rol El usuario cambia su rol actual por otro


de sus roles permitidos

Administrador Gestionar MI Permite que los usuarios con privilegios


gestionen la MI de las aplicaciones:
crear nuevos roles, agregar usuarios,
modificar los permisos sobre los
componentes, etc.

Usuario Gestionar Plugins El usuario accede al la información de


todos los plugins instalados y edita
parte de ella

Usuario Cambiar Visibilidad El usuario cambia la visibilidad de un


plugin

Usuario Eliminar Plugin El usuario elimina un plugin

Usuario Agregar Plugin El usuario instala un plugin en la


aplicación

Tabla 4.1: Resumen de los casos de uso

Proyecto Fin de Carrera | 48


4.4.2. Diagramas de Casos de Uso

Ilustración 6: Casos de uso para el subsistema de


documentos

Ilustración 8: Diagrama de casos de uso para el


subsistema Usuarios Ilustración 7: Diagrama de casos
de uso para el subsistema Plugin

Proyecto Fin de Carrera | 49


4.4.3. Operaciones del sistema identificadas

A partir de los casos de uso descritos en los puntos anteriores, se han identificado las
siguientes operaciones del sistema:

• AbrirDocumento(nombreDocumento)
• realizarAnotacion(Documento, Anotacion, x, y)
• cambiarPagina(Documento, numPagina)
• eliminarAnotacion(Documento, Anotacion)
• imprimirDocumento(Documento)
• guardarDocumento(Documento)
• subirFichero(pathFichero, pathDestino)
• crearCarpeta(nombreCarpeta, carpetaPadre)
• eliminarDocumento(nombreDocumento)
• moverDocumento(Origen, Destino)
• obtenerPropiedades(nombreDocumento)
• cambiarPermisos(nombreDocumento, nuevosPermisos)
• renombrarDocumento(original, nuevoNombre)
• iniciarChat()
• enviarMensaje(Mensaje)
• iniciarChatPrivado(Usuario)
• enviarMensajePrivado(Mensaje, Usuario)
• iniciarVC(Usuario)
• cambiarRol(nuevoRol)
• obtenerListadoPlugins()
• cambiarVisibilidad(Plugin, visible?)
• agregarPlugin(fichero)
• eliminarPlugin(Plugin)

Proyecto Fin de Carrera | 50


5. Análisis

A lo largo de éste documento se recogerán las diferentes entidades extraídas del estudio
detallado de los requisitos impuestos para la aplicación (tanto funcionales como no
funcionales).

A partir de lo extraído en ésta fase de análisis, posteriormente, se realizará un diseño del


sistema, donde se reflejen aspectos más orientados a la implementación, pero de gran
importancia, como puede ser la gestión de eventos distribuidos.

5.1. Identificación de clases, atributos y relaciones

Durante el análisis se han extraído los siguientes puntos, relativos a la división en clases
del problema (necesaria debido al uso de un lenguaje orientado a objetos para la
implementación), a los atributos que deberán tener éstas clases y a las relaciones entre
ellas:

• Deberá haber usuarios. Un usuario podrá tener un solo rol en un momento dado,
pero deberá contemplarse que tenga una lista de roles permitidos (para poder
cambiar de rol en cualquier momento).

• Un documento será una colección de páginas, cada una con una serie de
anotaciones. Los documentos deberán soportar permisos y tener un propietario (Un
usuario en un rol).

• Cada componente gráfico será una clase distinta.

• Un componente gráfico podrá estar compuesto por otros más simples.

• Para cada usuario se debe permitir asociar un permiso para cada componente
gráfico.

• Para cada rol se debe permitir asociar un permiso para cada componente gráfico.

• Un plugin será una forma especial de componente gráfico.

• Una aplicación será un conjunto de plugins y componentes gráficos.

Proyecto Fin de Carrera | 52


5.2. Diagrama de clases estático

Gracias a la identificación realizada durante la sección anterior, es muy fácil extraer un


diagrama que nos permita ver gráficamente todas las clases y relaciones entre ellas.

Ilustración 9: Diagrama de clases estáticos

Proyecto Fin de Carrera | 53


5.3. Modelado del comportamiento externo del sistema

En ésta sección del documento se tratará de describir el comportamiento del modelo ante
la interacción de los actores con él. Se describirán una serie de operaciones de gran
importancia en la fase de diseño del sistema y se mostrarán un conjunto de diagramas de
colaboración que permitan obtener una descripción gráfica completa de la interacción de
los actores y las clases entre sí.

Contratos del sistema

Las operaciones aquí descritas se corresponden con aquellas que se han considerado de
gran importancia para la fase de diseño e implementación del sistema. En base, serán
una explicación de las precondiciones y postcondiciones de éstas operaciones, así como
de las responsabilidades de las que se hará cargo el sistema al realizarlas.

Nombre abrirDocumento(nombreDocumento:String)
Responsabilidad Abre un documento para su visualización
Dependencias Ninguna

Precondición - El documento debe existir en el sistema

Postcondición - El documento se muestra

realizarAnotacion(d:Documento, a:Anotacion, x:int,


Nombre
y:int)
Crea una anotación en una posición determinada de un
Responsabilidad
documento
Dependencias abrirDocumento, cambiarPagina
- El documento d debe abrirse previamente.
- Las posiciones x e y deben ser >= 0 para que la anotación
Precondición se visualice correctamente.
- La anotación a debe estar situada dentro de los limites de
la página.

Proyecto Fin de Carrera | 54


Postcondición - La anotación se agrega al documento d en la página actual.

Nombre cambiarPagina(d:Documento, numPagina:int)


Cambia el número de página mostrado para un documento
Responsabilidad
actual
Dependencias abrirDocumento
- El documento d debe abrirse previamente
Precondición - El número de página debe estar entre los limites
establecidos para el documento d.
Postcondición - La página actual del documento cambia

Nombre eliminarAnotacion(d:Documento, a:Anotacion)


Responsabilidad Elimina una anotación de un documento
Dependencias abrirDocumento, cambiarPagina
- El documento d debe abrirse previamente
Precondición
- La anotación a debe existir
Postcondición - La anotación a se elimina del documento d

Nombre imprimirDocumento(d:Documento)
Responsabilidad Imprime un documento
Dependencias Ninguna
Precondición - El documento d debe existir
Postcondición - El documento d se imprime

Nombre guardarDocumento(d:Documento)
Responsabilidad Guarda el estado actual de un documento
Dependencias abrirDocumento
Precondición - El documento d debe estar abierto
- El estado del documento d se guarda de forma
Postcondición
persistente.

Nombre subirFichero(pathFichero:String, pathDestino:String)


Responsabilidad Agrega un fichero nuevo al sistema
Dependencias Ninguna
- El path del fichero debe existir de forma local al usuario.
- Se deben tener permisos para escribir en el path de
Precondición
destino.
- El path de destino debe existir.
Postcondición - El fichero se almacena en el sistema de forma persistente.
- Si el nombre del fichero es igual a otro en el path de

Proyecto Fin de Carrera | 55


destino y el usuario lo especifica así, se guarda una nueva
versión del fichero original.

crearCarpeta(nombreCarpeta:String,
Nombre
carpetaPadre:String)
Responsabilidad Crea una carpeta en la carpeta padre especificada
Dependencias Ninguna
- carpetaPadre debe ser un destino válido en el sistema
- nombreCarpeta no puede ser un nombre vacío ni repetido
Precondición dentro de la carpeta padre
- Debemos tener permisos suficientes para escribir en la
carpeta padre
Postcondición - La carpeta se crea en la carpeta padre

Nombre eliminarDocumento(nombreDocumento:String)
Responsabilidad Elimina un documento del sistema
Dependencias Ninguna
- nombreDocumento debe hacer referencia a un documento
existente en el sistema
Precondición
- Debemos tener permisos suficientes para eliminar el
documento
Postcondición - El documento se elimina

Nombre moverDocumento(origen:String, destino:String)


Responsabilidad Mueve un documento desde una carpeta a otra
Dependencias Ninguna
- El path de origen y de destino deben existir
Precondición - Debemos tener permisos suficientes en el path de destino
para escribir
Postcondición - La carpeta padre del documento se actualiza

Nombre obtenerPropiedades(nombreDocumento:String)
Responsabilidad Muestra las propiedades de un documento
Dependencias Ninguna
Precondición - El documento debe existir
Postcondición - Se muestran las propiedades del documento

Proyecto Fin de Carrera | 56


cambiarPermisos(nombreDocumento:String,
Nombre
nuevosPermisos:String)
Responsabilidad Cambia los permisos de acceso a un documento
Dependencias Ninguna
- El documento debe existir
- La cadena con los permisos nuevos debe ser válida
Precondición sintácticamente
- Debemos tener permiso de escritura sobre el documento
para poder cambiar los permisos o ser el propietario.
Postcondición - Los permisos del documento se actualizan

renombrarDocumento(original:String,
Nombre
nuevoNombre:String)
Responsabilidad Cambia el nombre de un documento
Dependencias Ninguna
- El documento original debe existir
- El nuevo nombre no puede ser vacío ni repetido dentro del
Precondición
directorio padre del documento
- Debemos tener permisos de escritura sobre el documento
Postcondición - El documento cambia de nombre

Nombre iniciarChat()
Responsabilidad Inicia un chat con los usuarios conectados del sistema
Dependencias Ninguna
Precondición Ninguna
- Se abre un canal de comunicaciones entre los usuarios
Postcondición
conectados del sistema

Nombre enviarMensaje(mensaje:String)
Envía un mensaje desde un usuario hasta el resto de
Responsabilidad
usuarios conectados
Dependencias iniciarChat
Precondición - El usuario debe haber abierto el chat previamente
Postcondición - El mensaje se muestra a los usuarios conectados

Proyecto Fin de Carrera | 57


Nombre iniciarChatPrivado(u:Usuario)
Responsabilidad Inicia un chat privado con un usuario conectado del sistema
Dependencias Ninguna
- El usuario u debe estar conectado al sistema
Precondición
- El usuario u debe aceptar el inicio de la conversación
- Se abre un canal de comunicaciones entre los dos
Postcondición
usuarios

Nombre enviarMensajePrivado(mensaje:String, u:Usuario)


Envía un mensaje desde un usuario hasta un usuario
Responsabilidad
concreto
Dependencias iniciarChatPrivado
- El usuario debe haber abierto el chat privado con u
Precondición
previamente
Postcondición - El mensaje se muestra al usuario u

Nombre iniciarVC(u:Usuario)
Responsabilidad Se inicia una videconferencia con el usuario u
Dependencias Ninguna
Precondición - El usuario u debe estar conectado
Postcondición - Se inicia la videconferencia entre los dos usuarios

Nombre cambiarRol(nuevoRol:Rol)
Responsabilidad Cambia el rol del usuario en el sistema
Dependencias Ninguna
- El nuevo rol debe estar entre los permitidos para el
Precondición
usuario
Postcondición - El usuario cambia su rol en el sistema

Nombre obtenerListadoPlugins()
Responsabilidad Obtiene la lista de todos los plugins del sistema
Dependencias Ninguna
Precondición Ninguna
Postcondición - Se ofrece una lista con todos los plugins del sistema

Proyecto Fin de Carrera | 58


Nombre cambiarVisibilidad(p:Plugin, visible:Boolean)
Responsabilidad Permite ocultar o mostrar un plugin del sistema
Dependencias obtenerListadoPlugins
Precondición - El plugin p debe ser válido en el sistema
Postcondición - El plugin se muestra o no según lo indicado

Nombre agregarPlugin(fichero:String)
Responsabilidad Agrega un nuevo plugin al sistema
Dependencias Ninguna
- El fichero debe contener un plugin válido para el sistema
Precondición
- El fichero debe existir de forma local al usuario
Postcondición - El plugin se agrega al sistema

Nombre eliminarPlugin(p:Plugin)
Responsabilidad Elimina un plugin del sistema
Dependencias Ninguna
Precondición - El plugin p debe existir
Postcondición - El plugin p se elimina del sistema
Tablas 5.1: Contratos del sistema

Proyecto Fin de Carrera | 59


Diagramas de colaboración

Los diagramas de colaboración permitirán mostrar de forma gráfica la interacción entre las
distintas clases y los actores. Como se podrá observar por la semejanza entre ellos, en la
realización del sistema jugará una parte fundamental el envío de eventos, el cuál deberá
ser detallado en la fase de diseño del sistema.

Ilustración 10: Diagrama de colaboración para la operación abrir documento

Ilustración 11: Diagrama de colaboración para la operación realizarAnotacion

Proyecto Fin de Carrera | 60


Ilustración 12: Diagrama de colaboración para la operación eliminarAnotación

Ilustración 13: Diagrama de colaboración para la operación imprimir

Proyecto Fin de Carrera | 61

Ilustración 14: Diagrama de colaboración para la operación


guardarDocumento
Ilustración 15: Diagrama de colaboración para la operación subirDocumento

Ilustración 16: Diagrama de colaboración para la operación crearCarpeta

Ilustración 17: Diagrama de colaboración para la operación eliminarDocumento

Proyecto Fin de Carrera | 62


Ilustración 18: Diagrama de colaboración para la operación moverDocumento

Ilustración 19: Diagrama de colaboración para la operación


obtenerPropiedades

Ilustración 20: Diagrama de colaboración para la operación cambiarNombre

Proyecto Fin de Carrera | 63


Ilustración 21: Diagrama de colaboración para la operación cambiarPermisos

Ilustración 22: Diagrama de colaboración para la operación iniciarChat

Ilustración 23: Diagrama de colaboración para la operación enviarMensaje

Proyecto Fin de Carrera | 64


Ilustración 24: Diagrama de colaboración para la operación iniciarChatPrivado

Ilustración 25: Diagrama de colaboración para la operación enviarMensajePrivado

Ilustración 26: Diagrama de colaboración para la operación iniciarVC

Proyecto Fin de Carrera | 65


Ilustración 27: Diagrama de colaboración para la operación cambiarRol

Ilustración 28: Diagrama de colaboración para la operación obtenerListaPlugins

Ilustración 29: Diagrama de colaboración para la operación cambiarVisibilidad

Proyecto Fin de Carrera | 66


Ilustración 30: Diagrama de colaboración para la operación agregarPlugin

Ilustración 31: Diagrama de colaboración para la operación


eliminarPlugin

Proyecto Fin de Carrera | 67


6. Diseño general del sistema

El diseño del sistema será la fase más cercana al proceso de implementación. Se


explicará paso a paso las soluciones adoptadas para cada uno de los problemas que se
plantean. Se realizará una especificación completa de todos los aspectos necesarios para
llevar a cabo el desarrollo del sistema: Diseño de la arquitectura, interfaz gráfica de
usuario, diseño de repositorios de datos, etc.

En cuanto al proceso de desarrollo, se realizará una mezcla del enfoque top-down (para
las aplicaciones en sí mismas) y bottom-up (para los elementos reutilizables, por ejemplo,
componentes gráficos).

Hay que destacar que los diagramas que se usarán, en la mayoría de los casos, no
seguirán el estándar UML, debido a que precisamente una de las carencias de éste es la
imposibilidad de modelar correctamente sistemas distribuidos.

JavaSpaces será considerado un middleware: Será el software que ofrecerá la


conectividad necesaria, mediante una serie de servicios de red, para que las aplicaciones
funcionen en plataformas heterogéneas. Debido a esta, en la mayoría de diagramas que
se presenten aparecerá JavaSpaces como el sistema de interconexión entre elementos
del sistema.
6.1. Diseño arquitectónico

La arquitectura de la aplicación final será del tipo cliente/servidor, debido a la necesidad


de mantener permanentemente un sistema de gestión de eventos producidos por los
clientes. Éste sistema serán los servidores, uno para gestionar los eventos relacionados
con la metainformación del sistema y otro orientado a la gestión de documentos.

Tanto los clientes como los servidores serán implementados siguiendo un esquema por
capas: Una capa de interfaz gráfica, una capa de modelo y una capa física, más cercana
al bajo nivel (conexiones de red, comunicación con hardware, comunicación con bases de
datos, etc.).

Los componentes gráficos que por su cometido no sean reutilizables (por ejemplo, la
ventana principal de la aplicación) serán creados siguiendo un modelo vista-controlador.
También se hará uso de una arquitectura par a par (peer to peer o P2P) para la
transmisión de datos (ficheros, imágenes, etc.) entre usuarios del sistema, para evitar la
sobrecarga de los servidores.

El cliente y el servidor se comunicarán mediante la tecnología JavaSpaces, con la que se


distribuirán los eventos producidos en los clientes.

Proyecto Fin de Carrera | 69


El sistema, en general tendrá la siguiente estructura completa:

Ilustración 32: Esquema general del sistema

En cuanto a la arquitectura de la aplicación cliente, esquemáticamente podríamos


resumirla mediante el siguiente diagrama:

De una forma más detallada,


viéndose claramente los tipos
de arquitecturas que se usarán
durante el desarrollo del
sistema, podemos observar el
siguiente diagrama:

Ilustración 33: Esquema general de una aplicación cliente

Proyecto Fin de Carrera | 70


Ilustración 34: Arquitectura del sistema

Haciendo uso de los diagramas anteriores, de la fase de análisis, y de los requisitos del
sistema se ha elaborado un diagrama de paquetes, cuyo esquema será el tomado para la
fase de implementación del sistema.

Ilustración 35: Diagrama de paquetes del sistema

Proyecto Fin de Carrera | 71


En cuanto al despliegue final del sistema, éste deberá de ser tal y como se muestra en el
siguiente diagrama:

Ilustración 36: Diagrama de despliegue del sistema

Proyecto Fin de Carrera | 72


6.2. Diseño de la interfaz gráfica

Principios

Los principios que han guiado el diseño de la interfaz serían:

1. Conocer a qué usuarios va destinado el sistema. Antes de preguntarnos qué va


a hacer el sistema y, por supuesto, antes de preguntarnos cómo lo va a hacer, la
cuestión clave es: ¿Quién va a usar el sistema?.

2. El principio de la metáfora. Tomar prestados comportamientos de sistemas que


los potenciales usuarios conocen. Por ejemplo, para indicar que si el usuario pulsa
un determinado botón eliminará un determinado elemento puede utilizarse un icono
que represente una papelera.

3. Las funciones proporcionadas por el sistema han de estar claramente


expuestas en el interfaz. Una funcionalidad que hipotéticamente sería de gran
utilidad para el usuario la pierde totalmente si para acceder a ésta el usuario tiene
que navegar por muchos menús (perdiendo gran cantidad de tiempo) para acceder
a ella o buscarla en "oscuros" paneles de preferencias.

4. Principio de coherencia.

! La coherencia interna significa que las conductas del programa tienen


mantienen la coherencia con respecto a otras partes del programa.

! Coherencia externa significa que el programa es coherente con el entorno en el


que se ejecuta.

Proyecto Fin de Carrera | 73


5. Principio de visualización del estado. Un cambio en el estado del programa
debe verse reflejado en un cambio en el interfaz.

6. Principio de "enfoque". Las partes más importantes de la interfaz gráfica deben


de destacar sobre aquellas que sean secundarias.

7. Principio de seguridad. Proporcionar al usuario una "red de seguridad".


Garantizar que las acciones que realiza el usuario no van a tener efectos
indeseables y/o que puedan deshacerse con facilidad.

8. Principio del contexto. Hay que limitar la actividad de los usuarios a su contexto.
Un conjunto de operaciones válidas en un contexto podrían no serlo en otro.

9. El principio estético. Es necesario establecer una serie de criterios estéticos a la


hora de diseñar el interfaz. No es necesario elaborar una "obra de arte", pero es
fundamental que la interfaz sea atractiva de cara al usuario.

10. Principio de las pruebas de usuario. En muchos casos, un buen diseñador de


software puede detectar defectos fundamentales en una interfaz de usuario. Sin
embargo, hay muchos tipos de defectos que no son tan fáciles de localizar y es
necesaria la participación del usuario.

11. Principio de humildad. A la hora de realizar el diseño es necesario tener en


cuenta a los usuarios y no intentar imponer nuestra visión sobre éstos.

Los puntos anteriores, en nuestra filosofía de desarrollo, los resumiremos a uno solo, que
mantendremos siempre por encima de todos los demás:

0. Principio K.I.S.S. (Keep It Simple, Stupid!): establece que la simplicidad en el


diseño debe ser un objetivo clave y que la complejidad innecesaria debe de ser
evitada.
Ventana Principal de la aplicación cliente

Proyecto Fin de Carrera | 74


En la versión definitiva del interfaz de la ventana principal tiene como eje principal el árbol
de documentos compartidos.

La idea de centrar el interfaz de usuario en el acceso a los documentos compartidos se


tomó de BSCW(Be Smart - Cooperate Worldwide), que es una plataforma pública de
colaboración en internet, desarrollado por OrbiTeam y Fraunhofer FIT.

Ilustración 37: Captura de la pantalla principal de la


plataforma BSCW

En el diseño, la ventana correspondiente a esta versión se divide en tres secciones:

• Norte. En ella se encuentra la barra de herramientas que permite el acceso a


distintas funcionalidades del sistema.

• Oeste. Se divide a su vez en dos zonas:

• Superior: Permite acceder a las mini-aplicaciones del sistema. Para


ejecutarlas sólo habrá que realizar doble click sobre el nombre de la
aplicación y esta se ejecutará inmediatamente.

• Inferior: muestra un árbol con los usuarios que se encuentran conectados


clasificados por su rol. Incorpora también una barra de herramientas que
permite realizar las tareas más comunes.

Proyecto Fin de Carrera | 75


Ilustración 38: Versión definitiva de la interfaz principal de la
aplicación
• Centro. Panel donde se visualizarán, en forma de árbol, los documentos
compartidos por los usuarios del sistema. Además, también incorporará una barra
de menús, a partir de la cual se podrá acceder a la funcionalidad que proporciona
el sistema en cuanto al manejo de documentos

Motivos aceptación:

• Gran importancia de los documentos compartidos para el sistema: Se establece un


equilibrio entre la importancia de los documentos y las aplicaciones del sistema.

Revisión de la Tercera Versión

Durante la implementación del sistema se han realizado una serie de cambios sobre la
versión tercera del interfaz:

• Eliminación de la barra de herramientas principal y desplazamiento de ésta al árbol


de documentos compartido.

Proyecto Fin de Carrera | 76


• Inclusión de una barra de progreso que permite informar al usuario del progreso de
algunas tareas que se ejecutan en segundo plano (como cargar un fichero desde la
red).

• Inclusión de la ayuda del sistema dentro de tooltips en cada uno de los elementos
de la interfaz

Los motivos que han provocado el cambio son los siguientes:

• La escasa funcionalidad que soportaba la barra de herramientas y el hecho de que


esta también estuviera en gran medida soportada por el menú.

• Necesidad de proporcionar al usuario cierta "conciencia" de determinados


procesos.

• Evitar que el usuario poco experimentado deba "navegar" entre cientos de páginas
de documentación para saber como se realiza una acción. Todo es accesible con
un sólo click y toda la ayuda está integrada en cada elemento del interfaz.

Ilustración 39: Versión revisada de la interfaz

Por último, el aspecto final de la ventana principal de la aplicación cliente, una vez

Proyecto Fin de Carrera | 77


implementada, sería tal y como se puede observar en la siguiente imagen:

Ilustración 40: Ventana principal de la aplicación

Ventana del Editor

El primer diseño de la ventana del editor incorporaba una barra de herramientas que
permitía acceder a las funciones más básicas (definir la figura y el color de las
anotaciones, navegar por el documento, guardar las anotaciones y deshacer) y el lienzo
donde se dibuja el documento:

Proyecto Fin de Carrera | 78


Ilustración 41: Imagen del primer prototipo del editor

Una segunda aproximación, agregó una nueva barra. En esta barra se incluyen los
controles para la navegación del documento. En la barra superior, se incluyen los
controles relativos a la anotación del documento tales como guardar las anotaciones,
imprimir el documento con las anotaciones, desplazarnos a lo largo de las anotaciones
cambiar el tipo de anotación, el color, eliminar anotaciones deshacer, rehacer, etc.

Ilustración 42: Diseño definitivo del interfaz del editor de documentos

Proyecto Fin de Carrera | 79


6.3. Decisiones de diseño tomadas para la consecución de los objetivos del
sistema

• Plataforma de componentes gráficos replicados. Se implementarán


componentes gráficos comunes que permitan el envío, recepción y procesamiento
de eventos, tanto de forma local como remota. Se podrá enviar un evento a tres
destinos: A un cliente concreto (incluido el local), a un grupo de clientes o a todos
los clientes.

• Integración de todas las aplicaciones en un único sistema. Creación de una


plataforma sobre la que funcione un sistema de plugins. Éste sistema de plugins
permitirá integrar tantas aplicaciones como sean necesarias en un único sistema.
Podrán comunicarse entre sí mediante eventos específicamente diseñados e
implementados con ese fin.

• Extensibilidad. El framework será fácilmente extensible gracias a una división por


capas que permitirá que la realización de un nuevo componente o funcionalidad no
requiera la reescritura de capas de abstracción inferiores. Todos los componentes
implementados podrán ser reutilizados para la creación de componentes más
complejos para futuras versiones del framework. La plataforma será fácilmente
extensible gracias al uso de plugins.

• Portabilidad. Para que el sistema funcione en múltiples plataformas se ha usado el


lenguaje de programación Java. La aplicación tendrá igual funcionamiento en
cualquier SO que admita la instalación de la máquina virtual de Java (JVM).

• Registro de usuarios y asignaciones de rol a éstos. Se creará un subsistema de


gestión y almacenado de metainformación del sistema. En ésta metainformación se
almacenará el registro de usuarios y asignaciones de roles, además de los
permisos para cada componente.

• Gestión de un conjunto de documentos (y directorios) compartidos. Se


implementará un subsistema de gestión de metainformación de documentos. Cada
documento deberá tener permisos, un usuario propietario y un rol con el que ese
usuario creó el documento. Un directorio será un documento con permisos
especiales (parecido al esquema que siguen los SO's tipo UNIX). Cada evento

Proyecto Fin de Carrera | 80


producido por un cliente en un documento deberá distribuirse al resto de clientes
del sistema.

• Anotación colaborativa de documentos de distintos formatos (imágenes, pdf,


etc.). Un documento será una abstracción sobre cualquier formato de documento.
Básicamente, serán una colección de imágenes (una por página) que se
corresponderá con el resultado del “renderizado” de cada página del formato
original (convertir cada página del formato original a un mapa de bits). El sistema
deberá tener filtros de conversión de formatos permitidos a formato Documento.
Una anotación sobre un documento será un conjunto de figuras geométricas con
datos acerca del usuario, el rol y la fecha y hora en la que se dibujaron, además de
una posición en la página correspondiente donde se crearon. Cuando se abre, se
cierra o se anota sobre un documento, se deberá enviar eventos al resto de
clientes informando sobre éstas acciones.

• Comunicación entre los usuarios.

• Servicio de mensajería instantánea: Creación de un chat para la


comunicación entre clientes del sistema.

• Servicio de e-mail: Envío de mensajes asíncronos. Éstos mensajes serán


ficheros que se escribirán en una carpeta especial (“Incoming”) y que solo
serán visibles para los usuarios a los que vaya dirigido el mensaje. Se
deberá crear un filtro específico para que los mensajes se interpreten como
Documentos del sistema.

• Servicio de Videoconferencia: Creación de un subsistema dedicado


exclusivamente a la captura, transmisión y reproducción de audio y vídeo
para cada cliente.

• Conciencia de grupo (awareness). Se crearán servidores encargados de recibir


enviar, recibir y procesar los eventos dedicados al awareness. Cada evento será
reenviado correspondientemente a los distintos clientes del sistema. Éstos eventos
actuarán sobre los componentes implementados, variando las posibilidades de
interacción con éstos.

Proyecto Fin de Carrera | 81


Con respecto a los objetivos propios del framework, tendremos lo siguiente:

• Usabilidad. Se seguirán una serie de principios de diseño para que el sistema sea
de fácil uso. Se hará un especial empeño en la simplificación en lo posible del uso
del sistema, mediante el uso de interfaces gráficas que permitan el acceso a los
componentes de una forma rápida y directa.

• Eficiencia. En cuanto a la eficiencia del sistema, se realizarán los procesamientos


que requieran de un mayor uso de recursos en hebras distintas de la hebra
principal de la aplicación cliente. En cuanto a las transmisiones de datos, la
transmisión de elementos con gran cantidad de información, tales como ficheros
completos, imágenes, estructuras de datos complejas, etc. se realizarán mediante
sockets o haciendo uso de la tecnología RMI.

• Fácil Desarrollo. Se seguirá una arquitectura por capas que permitirá en un futuro
reemplazar su implementación por otra sin necesidad de cambiar la
implementación del resto de capas, al menos, en gran medida. El código será
estructurado en paquetes con una funcionalidad específica, intentando limitar en lo
posible el acoplamiento entre éstos. Se seguirán estándares en el formateo del
código fuente que aumentarán la legibilidad de éste. Además, se documentará
ampliamente. Los componentes gráficos seguirán el sistema de desarrollo
impuesto para JavaBeans, de tal forma que puedan ser usables mediante un IDE
que posea un editor gráfico de interfaces de usuario. Se distribuirá una biblioteca
en un único fichero que permitirá utilizar el framework para la realización de nuevas
aplicaciones, así como un manual para los desarrolladores para ésta.

Proyecto Fin de Carrera | 82


6.4. Subsistemas identificados

Tras el análisis de las distintos subproblemas derivados de la realización del sistema


completo, así como de los objetivos marcados para la solución de éstos, se han detectado
los siguientes subsistemas:

Subsistemas específicos para el framework (núcleo del sistema). Todo éstos subsistemas
se caracterizarán por proporcionar servicios para la implementación de cualquier
aplicación que haga uso del framework:

! Gestión de eventos del sistema: Servicios básicos de comunicación entre las


aplicaciones que conforman el sistema (clientes y servidores).
! Gestión del repositorio de datos del sistema: Servicios básicos para el
almacenamiento persistente de metainformación del sistema.
! Gestión de metainformación de aplicaciones: Servicios básicos de distribución de
metainformación de aplicaciones entre clientes.
! Gestión de metainformación de ficheros: Servicios básicos de distribución de
metainformación de ficheros entre clientes.
! Subsistema de transmisión de datos: Servicios básicos de transmisión directa de
ficheros entre clientes.

Subsistemas específicos para la plataforma implementada:

! Subsistema de gestión de documentos: Modelado y visualización de documentos


! Subsistema de edición compartida de documentos: Anotación de documentos.
! Subsistema de videoconferencia: Videoconferencia entre clientes.
! Subsistema de plugins: Creación de plugins para la ampliación de la funcionalidad
de la plataforma.
! Aplicación cliente

Proyecto Fin de Carrera | 83


7. Diseño de subsistemas

En ésta sección se tratará de identificar y detallar exhaustivamente todos los subsistemas


de los que se compondrá el sistema final. Para cada subsistema, se realizará una
explicación de su funcionamiento global, una descripción de los recursos usados para
poder solucionar los problemas más importantes encontrados, y, por último, el conjunto de
clases que formarán el subsistema, junto con un diagrama UML que especifique además
los atributos, operaciones y relaciones que hay entre ellas. Además, se volverá a mostrar
el diagrama de arquitectura del sistema en cada caso para poder observar la situación
dentro de cada elemento del subsistema desarrollado.

7.1. Subsistemas específicos del framework

Se proporcionan diversos subsistemas que aportarán la funcionalidad básica necesaria


para cualquier aplicación creada mediante el framework, incluyendo, por tanto, la
plataforma que se implementará.
7.1.1 Gestión de eventos del sistema

Éste subsistema estará dedicado a la recepción y envío de eventos distribuidos de cara al


cliente. Para que un cliente reciba o envíe eventos deberá conectarse a un canal de
comunicaciones con el servidor al que estén dirigidos (tendremos un servidor para la
metainformación y otro para la gestión de ficheros). En nuestro caso, el canal de
comunicaciones será JavaSpaces.

Para que el sistema sea ajeno al uso de JavaSpaces se debe proporcionar una serie de
clase que actúen de capa de abstracción sobre éste. Éstas clases serán las usadas por
cualquier elemento del sistema para el envío y recepción de eventos. También habrá que
realizar una abstracción acerca del servidor al que se dirigen los eventos del cliente, es
decir, ésto debe ser transparente, en la medida de lo posible para el resto de subsistemas.

Debido a que cada componente susceptible de enviar o recibir un evento requerirá de


características específicas (supongamos un botón: tendremos que adaptar los eventos
para detectar un click) se crearán también abstracciones sobre los eventos, es decir, se
evitará que los otros subsistemas deban lidiar con interfaces “Entry” para JavaSpaces. Se
debe también permitir la sincronización de componentes distribuidos mediante el uso de
eventos especiales dedicados a ésta cuestión. Para algunos casos específicos, se deberá
permitir que los eventos se escriban de forma ordenada en el JavaSpaces, con lo que
tendremos que incluir mecanismos de abstracción para ello.

Si en un futuro se tomase la decisión de cambiar el canal de comunicaciones, éste


subsistema debe ser lo suficientemente bien diseñado como para que éste cambio no
requiera ningún cambio en el resto de subsistemas.

En resumen, deberemos especificar una abstracción para el envío y recepción de eventos


a través de JavaSpaces, para la conexión con los servidores y para los eventos
propiamente dichos.

Proyecto Fin de Carrera | 85


Conector para JavaSpaces (DConector)

El DConector es una capa de abstracción gracias a la cual se descargar de bastante


complejidad a los componentes. Él es el que se encarga de realizar el envío y recepción
de eventos desde/hacia el JavaSpace.

Cuando un usuario se conecte al sistema como cliente, ésta clase deberá almacenar la
metainformación de éste, requerirle su nombre de usuario y su contraseña y, en caso de
que sea necesario, encargarse de la sincronización de los componentes para que el
usuario se encuentre gráficamente con el mismo estado que el resto de usuarios.

En cuanto a la gestión de errores, se encargará de mantener hebras que detecten


posibles fallos en la conexión y desconecte adecuadamente al usuario, mostrando
previamente los mensajes oportunos.

Un componente que desee enviar un evento le será suficiente con colocarlo en una cola
de eventos que dispone el DConector y será este el que haga el envío efectivo. Para
realizar dicho envío se usa el algoritmo basado en un token descrito con anterioridad para
garantizar una correcta numeración de los eventos.

Cuando el DConector recibe un evento éste lo pasará al componente al que vaya


destinado (recordamos que cada componente estará identificado por número único dentro
de la aplicación).

Además del envío y recepción de eventos se encarga de todas las tareas de inicialización,
tanto propias como lazar el cliente de metainformación. Durante la inicialización es el que
notifica a los componentes cuando deben realizar el envío de su petición de inicio de
sincronización, si es que necesitan hacerlo.

A la hora de salir un usuario de la aplicación también es el DConector el encargado de


notificar dicha salida para que se haga de una forma correcta.

Proyecto Fin de Carrera | 86


La clase tendrá un conjunto de hebras que se especifican a continuación:

! Hebra localizadora. Se encargará de localizar el JavaSpaces. Ésta hebra evita que


la aplicación se bloquee hasta localizar el JavaSpaces.

! Hebra detectora de error. Se encargará de localizar errores de detección del


JavaSpaces. Si pasados 10 segundos del inicio de la localización por parte de la
hebra localizadora aún no hemos obtenido respuesta, entonces se considerará que
el JavaSpaces no está disponible y se avisará al usuario. Después, se terminará la
aplicación.

! Hebra consumidora. Permite procesar los eventos recibidos en el cliente. Se


dispondrá de una cola de eventos que se irá procesando en orden FIFO. Los
eventos serán escritos en el JavaSpaces, agregándoles previamente el nombre de
usuario, aplicación, origen y destino del evento.

! Hebra recolectora. Se encargará de recibir eventos. Se detectará el componente al


que va dirigido el evento y se enviará a éste para su procesamiento. Cada
componente deberá tener un método de procesamiento adecuado.

El proceso de envío de un evento a través del DConector sigue el siguiente esquema:

Proyecto Fin de Carrera | 87


Ilustración 43: Diagrama de secuencia para el envío de eventos

Puesto que se requiere de una sincronización en las hebras anteriormente descritas, se


deberá implementar un monitor Java adecuado para ello. Éste monitor deberá tener
métodos para modificar y leer en exclusión mutua tres variables compartidas: Una para
detectar si ocurrió un error en la detección de JavaSpaces, otra para comprobar si los
componentes han sido sincronizados y otra para comprobar si se ha inicializado todo
correctamente o no.

El siguiente diagrama de secuencia muestra el proceso de inicialización del DConector:

Proyecto Fin de Carrera | 88


Ilustración 44: Diagrama de secuencia de la inicialización del DConector

Ésta clase deberá mostrar gráficamente un pequeño diálogo donde se muestre el hecho
de estar sincronizando elementos y otro que permita introducir el nombre de usuario y la
contraseña. El diseño de ambos componentes gráficos se muestra a continuación.

Proyecto Fin de Carrera | 89


Ilustración 45: Ventana de login y ventana de sincronización

Los siguientes datos del sistema deberán ser accesibles para el cliente desde ésta clase:

• Nombre de usuario
• Clave
• Rol desempeñado actualmente
• Rol por defecto
• Aplicación en ejecución

Los siguientes métodos serán los permitidos por ésta clase para el cliente:

• Inicializar: Mostrar el dialogo de login, sincronizar y ejecutar las hebras


anteriormente descritas. Deberá también establecer una conexión con el
subsistema de gestión de eventos a través de una instancia de la clase
ClienteMetainformación. Ésta clase se detallará en la sección dedicada al
subsistema de gestión de eventos.

• Obtener la cola de eventos.

• Sincronizar componentes.

• Salir (permitirá salir correctamente, comunicando la desconexión del usuario).

• Obtener el DConector en ejecución (solo podrá haber una instancia del Dconector
en ejecución por cada cliente).

Proyecto Fin de Carrera | 90


• Consultar los usuarios que hacen uso de un token para la escritura ordenada de
eventos.

• Leer un token para la escritura ordenada de eventos.

• Escribir un token para la escritura ordenada de eventos.

• Terminar el uso de un token por parte de un usuario. Se decrementará el número


de usuarios que hacen uso del token. Si no quedan usuarios, éste se eliminará.

El uso de tokens para escritura ordenada de eventos se explicará detalladamente en


secciones posteriores de éste documento.

Abstracción sobre los eventos (Devent)


En el sistema, los eventos serán abstracciones sobre la clase “Entry”, que es el único
elemento que se puede escribir en JavaSpaces. Se definirá un evento abstracto llamado
Devent que definirá una serie de propiedades por defecto que deberán tener el resto de
eventos. Éstas propiedades serán las siguientes:

• Origen del evento


• Destino del evento (se establecerá un destino especial para referirse a todos los
usuarios o a un subconjunto de ellos).
• Número de secuencia del evento
• Nombre del usuario que genera el evento
• Rol actual del usuario que genera el evento
• Tipo de evento (identificador numérico)
• Aplicación que genera el evento
• Nombre del componente que genera el evento
• Número de secuencia del último evento procesado por el componente que genera
el evento.
• Evento adjunto al evento (otro Devent encadenado)

Proyecto Fin de Carrera | 91


Los eventos serán almacenados en los clientes mediante una cola implementada en la
clase ColaEventos. Será básicamente un monitor Java que gestiona la escritura y lectura
de un vector. Es necesario que la cola sea un monitor, puesto que diversas hebras del
cliente intentarán acceder a la vez al vector que guarda los eventos. Ésta cola tendrá
operaciones para introducir un evento, extraer un evento, medir el número de elementos
que la componen y comprobar si está vacía.

Se implementará así mismo un evento especial que permita enviar y recibir eventos con la
metainformación del sistema completo. Éste evento se conocerá como DMIEvent.
Permitirá notificar y obtener respuestas de notificación para inserción, eliminación o
modificación de usuarios, roles, componentes, aplicaciones, etc. También permitirán
notificar y obtener notificaciones para la conexión y desconexión de usuarios.

Escritura ordenada de eventos (Tokens)

Para mantener un estado consistente, hay que garantizar que todos los eventos se
procesan en el orden en que fueron enviados.

El primer paso necesario es tener un número de secuencia que nos permita diferenciar
qué eventos se han producido antes o después de qué otros. A este número de secuencia
se le va a denominar a partir de ahora contador. Un contador menor indicará que el
evento se ha producido antes que otro que tenga un contador mayor. Cuando un
componente sincroniza su estado con el de las demás instancias de ese componente
(puede haber componentes que no realicen sincronización) también sincroniza el contador
a partir del cual comenzará procesar eventos. Así pues si un componente sincroniza su
contador al valor 357 esperará hasta recibir el evento con contador 358. Una vez recibido
éste esperará hasta recibir el 359 y así sucesivamente, siempre con incremento de una
unidad en el número de evento que se espera. Para que esto funcione debe garantizarse
que los eventos se numeran en orden ascendente y que no se envían 2 eventos con un
mismo contador. Para ello existe un único token que un usuario que desee enviar un

Proyecto Fin de Carrera | 92


evento deberá coger antes de poder realizar el envío. Este token contendrá el número de
secuencia (contador) que deberá asignarse al evento a enviar. Una vez numerado se
procederá al envío del evento tras el cual se incrementará el contador el token en una
unidad depositándolo de nuevo en su lugar. Será en ese momento cuando otro usuario
que esté a la espera o que posteriormente desee escribir un evento pueda coger el token
y realizar el mismo proceso. Gracias a este pequeño algoritmo garantizamos que solo
habrá un usuario al mismo tiempo enviando un evento y que la numeración de los eventos
se realiza de forma correcta.

Un caso particular del uso de token son los TokenFichero, que está asociado a la
anotación compartida de documentos. Por cada documento que se esté abierto en un
momento dado en el sistema, existirá un TokenFichero correspondiente a ese documento.

Diagrama de clases del subsistema

A continuación se mostrará un diagrama UML con lo especificado con anterioridad, pero


con una mayor orientación a la implementación final del subsistema.

Proyecto Fin de Carrera | 93


Ilustración 46: Diagrama de clases del subsistema

Proyecto Fin de Carrera | 94


7.1.2 Gestión del repositorio de datos del sistema

En el sistema, será necesario el almacenamiento persistente de la metainformación. Para


realizar éste almacenamiento persistente se ha optado por un repositorio de datos,
implementado mediante una base de datos. La aplicación que nos aportará la
funcionalidad de la base de datos será MySQL. Deberemos realizar una serie de clase
que nos aporte mecanismos de abstracción para que si en futuro se desea implementar
otro mecanismo de almacenamiento, u optar por otra aplicación de BD, el cambio sea
relativamente sencillo. Se deberán aportar mecanismos de abstracción para la conexión
con la BD, el envío de comandos con formato SQL a ésta y la conversión de los datos
recibidos desde la BD a objetos de fácil uso por otros subsistemas.

Se deberá impedir, usando ésta filosofía, que en cualquier otro subsistema se deba
realizar un “acceso directo” a la BD o se deba usar un comando de SQL para realizar
alguna operación concreta.

Conector con la base de datos (ConectorBD)

Se deberá implementar una clase específica para realizar la conexión con la base de
datos. Gracias a ésta clase, se hará transparente para el resto de subsistemas el hecho
de que se esté usando un tipo específico de gestor de bases de datos. Si en cualquier
momento se tomase la decisión de sustituir MySQL, tan solo se debería modificar ésta
clase.

La filosofía seguida para la implementación de ésta capa de abstracción será la de


intentar hacer similar su funcionamiento al de un flujo de datos en un fichero, con la
ventaja de que interpretaremos comandos SQL para insertar, actualizar, eliminar o
recuperar los diversos contenidos. Bajo ésta filosofía, deberemos implementar métodos
que nos permitan realizar las siguientes operaciones:

Proyecto Fin de Carrera | 95


• Abrir un flujo con la base de datos
• Cerrar el flujo con la base de datos
• Insertar
• Actualizar
• Eliminar
• Recuperar
• Generar un identificador único para un elemento (para poder insertar nuevos
elementos que tengan como clave primaria un identificador que no se corresponda
con ningún elemento de la realidad)

Puesto que la base de datos normalmente se encontrará de forma remota al usuario de


ésta, entonces se deberá proporcionar un fichero de configuración donde se especifique
la dirección IP del sistema que la albergue, así como un nombre de usuario y una
contraseña válidos. Para que no se dedique un fichero completo a éste cometido,
entonces, en el fichero de configuración que se utilice para los servidores del sistema se
integrará una línea con la siguiente sintaxis:

MIBD: ip_gestor_bd nombre_usuario password

El formato completo de éste fichero de configuración se detallará en los subsistemas


correspondientes a los servidores de metainformación.

Gestores de la bases de datos (GestorMetainformacionBD y GestorFicherosBD)

Para gestionar el contenido del repositorio y abstraer el hecho de que se esté usando una
base de datos, se crearán dos clases específicamente destinadas a la gestión de la
metainformación de las aplicaciones y de los ficheros. Gracias a éstas clases, si se optase
por reemplazar el almacenamiento en una base de datos por otro esquema de
almacenamiento (por ejemplo, un fichero), tan solo se debería sustituir la implementación
de las operaciones de cada una de ellas, sin necesidad de alterar el resto de subsistemas.
Éstas clases se encargarán también de traducir los resultados obtenidos de la base de
datos a objetos de diversas clases de la capa de modelo del sistema.

Proyecto Fin de Carrera | 96


La clase dedicada a la gestión de la metainformación de las aplicaciones
(GestorMetainformacionBD) permitirá recuperar el contenido completo dedicado a ésta
cuestión en la base de datos, así como, dado un conjunto de datos de metainformación,
insertar, borrar o actualizar debidamente. También se permitirá la creación de logs de
acceso al sistema para tener un cierto control de los accesos producidos a éste. La
metainformación de cada aplicación estará compuesta por una colección de
metainformación dedicada a los usuarios, roles y componentes que la formen.

En cuanto a la clase dedicada a la gestión de la metainformación de los ficheros


(GestorFicherosBD), se permitirán operaciones para recuperar todos los ficheros,
recuperar el contenido de un cierto directorio, recuperar el directorio padre de un fichero,
insertar metainformación de ficheros, buscar ficheros mediante su identificador único,
buscar ficheros mediante su path, modificar la metainformación de un fichero y eliminar
ficheros o directorios. Cabe destacar que el hecho de que la diferencia entre un fichero y
un directorio será meramente un valor en uno de los campos de la metainformación (tal y
como ocurre en los sistemas tipo UNIX), con lo que serán tratados de forma homogénea.

El diagrama UML asociado a ambas clases se muestra a continuación.

Proyecto Fin de Carrera | 97


Ilustración 47: Diagrama de clases del subsistema de gestión del repositorio

Proyecto Fin de Carrera | 98


Modelo E/R de la base de datos asociada al sistema

A continuación se expone el proceso de modelado de la base de datos del sistema. En un


primer momento se pensó en diseñar dos bases de datos, una para la metainformación
del sistema y otra para los ficheros. Pronto se comprobó que no era necesario debido a
que los ficheros son gestionables mediante una sola tabla de una base de datos.

Las entidades, relaciones y atributos que se utilizarán para construir el modelo E/R de la
base de datos han sido identificadas a continuación.

Entidades encontradas:

• Aplicación. Identifica a cada una de las aplicaciones de las que se almacenará


metainformación. En el caso específico de éste sistema a desarrollar, tan solo
tendremos una, pero deberá darse soporte para que otros desarrollos futuros
puedan tener metainformación propia a sus aplicaciones.

• Rol. Representa a cada uno de los roles que se pueden desempeñar en las
distintas aplicaciones.

• Usuario. Representa a cada uno de los posibles usuarios que pueden actuar como
clientes para las distintas aplicaciones.

• Componente. Identifica a cada uno de los distintos componentes gráficos de cada


una de las aplicaciones. Ésto será necesario debido a que cada componente
gráfico deberá mantener metainformación acerca de los niveles de acceso para
cada usuario y rol.

• Fichero. Identifica a cada uno de los distintos ficheros del sistema. Los ficheros
serán compartidos entre aplicaciones, con lo que no existirá ningún campo
orientado a identificar la aplicación a la que pertenece cada uno.

Proyecto Fin de Carrera | 99


Relaciones encontradas:

• Aplicación-Componente. Indica que un componente determinado pertenece a


una aplicación concreta

• Aplicación-Usuario. Indica qué usuarios pueden acceder a la aplicación

• Aplicación-Rol. Indica qué roles están permitidos en una aplicación

• Usuario-Rol. Indica los roles permitidos para un usuario y su rol por defecto

• Usuario-Componente. Indica los permisos que tiene un determinado usuario


sobre un componente

• Rol-Componente. Indica los permisos que tiene un determinado rol sobre un


componente

• Usuario-Fichero. Indica el propietario de un fichero. La raíz del sistema de ficheros


será el único fichero que no tenga propietario.

• Rol-Fichero. Indica el rol que tenía el propietario cuando creó el fichero. La raíz del
sistema de ficheros será el único fichero que no tenga rol del propietario, ya que
éste no existe.

• Fichero-Fichero. Indica el directorio padre de un fichero. Habrá un caso especial,


que será la raíz del sistema de ficheros, la cuál no tendrá ningún padre.

Proyecto Fin de Carrera | 100


Atributos encontrados (Con sus respectivas entidades/relaciones asociadas)

• Aplicacion(Nombre, nivel)
• Rol(Nombre)
• Usuario(Nombre, RolPorDefecto, Administrador)
• Componente(Nombre)
• Componente-Usuario(usu, comp, permisos)
• Componente-Rol(rol, comp, permisos)
• Fichero(nombre, es_directorio, permisos, directorio_padre, ruta_local, tipo)

Seguidamente, se ha procedido a generar el modelo Entidad/Relación de la base de


datos. Éste modelo se muestra a continuación.

Ilustración 48: Diagrama Entidad/Relación del repositorio

Finalmente, se ha trasladado el modelo E/R al modelo relacional, transformando las


entidades y/o relaciones en tablas, cuya traducción al lenguaje SQL será trivial.

Aplicación(ID_app, nombre, nivel)

Proyecto Fin de Carrera | 101


Componente(ID_cmp, nombre, ID_app)
Rol(ID_rol, nombre)
Usuario(ID_usu, nombre, ID_rol_defecto, administrador)
Fichero(id_fichero, nombre, es_directorio, permisos, usuario, rol, padre, ruta_local, tipo)

posibleR(ID_rol, ID_app)
posibleU(ID_usu, ID_app)
permitidos(ID_usu, ID_app)
permisosR(ID_rol, ID_cmp, nivel)
permisosU(ID_usu, ID_cmp, nivel)

Para facilitar la instalación del sistema se implementarán una serie de scripts que
permitan crear la base de datos y rellenarla con datos de prueba. Éstos scripts deberán
de ser provistos junto con la implementación final de la aplicación.

Proyecto Fin de Carrera | 102


7.1.3 Gestión de metainformación de aplicaciones

El objetivo este subsistema es proporcionar la funcionalidad necesaria para que la


metainformación relativa a las distintas aplicaciones (usuarios y roles permitidos, permisos
para los componentes, información de usuarios –como la lista de los roles permitidos
para un usuario–, usuarios conectados en un determinado momento, etc.) pueda ser
distribuida por el sistema a partir de la información almacenada en el repositorio de datos.
Así mismo, este subsistema también se encarga de realizar las comprobaciones
necesarias para garantizar que se cumplen las restricciones de acceso a las aplicaciones
y/o componentes. Por otro lado, el subsistema también proporcionará un mecanismo que
permita la modificación de la metainformación del sistema de forma gráfica.
En la siguiente figura se muestra el funcionamiento básico de este subsistema1:

Ilustración 49: Esquema arquitectónico de el subsistema de gestión


de la metainformación de la aplicación

1 A pesar de estar incluídos en el diagrama, las clases GestorMetainformaciónBD y ConcectorBD, estas clases no
serán especificadas en este punto.

Proyecto Fin de Carrera | 103


En él, podemos observar cómo se realiza el intercambio del tipo de información
especificada anteriormente:

• Cada vez que una aplicación cliente necesita de algún tipo de información de
awareness o de control de acceso a los componentes, el Componente en cuestión
envía un mensaje al Dconector.

• El Dconector, a su vez, envía otro mensaje al Cliente de Metainformación.

• El Cliente de Metainformación, envía un evento al JavaSpace con destino al


Servidor de Metainformación.

• El servidor recibe el evento y, en función del tipo de información requerida


procederá de la siguiente forma:
$ Si dispone de la información de forma inmediata, responde al cliente mediante
un nuevo evento escrito en el JavaSpace
$ Si no dispone de esa información, desplaza la consulta a la capa inferior, hasta
llegar como máximo a la Base de Datos. Una vez obtenida la información, ésta
rehace su camino hasta llegar de nuevo al Servidor, que responde al cliente
mediante un nuevo evento escrito en el JavaSpace

• El cliente lee el evento del JavaSpace, y devuelve la información al Dconector, que


a su vez la devuelve al componente.

• El componente realiza las acciones necesarias de acuerdo con la información


recibida.

Obviamente, el proceso anterior también puede extenderse a la modificación de


información (cambio de rol de un usuario determinado, por ejemplo).

Proyecto Fin de Carrera | 104


Además de los elementos involucrados en el anterior esquema, en este subsistema se
incluyen una serie de clases que permiten representar la metainformación del sistema
(usuarios, roles, componentes, etc.). Las clases serán las siguientes:

• MIAplicación
• MIUsuario
• MIRol
• MIComponente
• MICompleta

Por otro lado, las clases involucradas en este subsistema incluyen mecanismos de
detección y recuperación de errores (servidores caídos, clientes colgados, etc.), lo que
redunda en la fiabilidad y robustez del sistema.

Clases Involucradas

• AlmacenMetainformación. Se encarga de gestionar y almacenar la


metainformación del sistema. Provee de acceso a ésta al ServidorMetainformación.
Esta clase mantiene una lista con la metainformación de todas las posibles
aplicaciones cliente que pueden conectarse al sistema.
Ofrece una serie de métodos que permiten consultar y modificar la
metainformación del sistema.
Una vez arranca el servidor, esta clase se encarga de recuperar la metainformación
desde el repositorio.

• ClienteMetainformacion. Se encuentra en las aplicaciones cliente. Se encarga de


la comunicación con el servidor.
Al arrancar una aplicación cliente, se encarga de gestionar la autenticación del
usuario, dejando bloqueada la aplicación hasta que ésta no se halla realizado con
éxito.

ClienteMetainformacion almacena una lista de “listeners” (DMIListener's) que están

Proyecto Fin de Carrera | 105


a la escucha de posibles cambios en la metainformación del sistema. Será
responsabilidad de ClienteMetainformacion difundir estos cambios entre los
listeners. Estos listeners se corresponden con los componentes que conforman la
aplicación.

Esta clase incluye un mecanismo de detección de error que permite que si se


produce algún fallo a la hora de la conexión con el servidor, la aplicación no puede
continuar con su ejecución.

Con el objetivo de garantizar la correcta sincronización a la hora de localizar el


JavaSpace, la clase incorpora un monitor que
garantiza que no se realiza ninguna actividad
hasta que se halla tenido lugar la correcta
sincronización con el servidor. Este monitor
también proporciona la funcionalidad necesario
para comprobar si la sincronización se ha
llevado a cabo con éxito.

Ilustración 50: Diagrama de estados La clase cuenta con una serie de hebras:
para el monitor del cliente de
metainformación
#Hebra localizadora: es la encarga de localizar

el JavaSpace. Una vez localizado, notifica esta condición haciendo uso del
monitor.

# Hebra detectora de error: controla los posibles errores que podrían producirse
durante la localización del JavaSpace, si transcurrido un tiempo prudencial no
se ha localizado el JavaSpace, se indicará la condición de error y la aplicación
terminará. El funcionamiento es bien sencillo: la hebra se duerme un tiempo
establecido, transcurrido el cual comprueba si se ha localizado el JavaSpace, si

Proyecto Fin de Carrera | 106


esto es así, termina la hebra; en caso contrario, se notifica el error mediante el
Monitor.

# Hebra KeepAlive, se encarga de garantizar que el Servidor es consciente de


que el usuario sigue conectado. Envía un evento KeepAlive al servidor cada 30
segundos.

# Hebra Recolectora: es la responsable de gestionar los eventos recibidos por el


cliente; estos eventos serán enviados por el Servidor de Metainformación para
indicar cambios en la metainformación del sistema, siendo el cliente de
metainformación el encargado de difundir estos cambios entre los componentes
de la aplicación.

• MIAplicación. Encapsula la metainformación asociada a una aplicación.


A parte de la información propia de la aplicación, contiene una lista con todos los
usuarios admitidos para esa aplicación, otra lista para los roles permitidos y otra
para los componentes.
Proporciona métodos que permiten acceder y modificar la información almacena en
la clase.

• MIUsuario. Encapsula la metainformación asociada a un usuario.


A parte de la información propia de un usuario (nombre, clave, etc.), contiene una
lista con todos los roles permitdos para el usuarios y otra lista con los permisos de
acceso para los componentes y el rol por defecto del usuario.
Proporciona métodos que permiten acceder y modificar la información almacena en
la clase.

• MIRol. Encapsula la metainformación asociada a un rol. Hereda de MIUsuario.


A parte de la información propia de un rol, contiene una lista con los permisos de
acceso para los componentes.
Proporciona métodos que permiten acceder y modificar la información almacena en
la clase.

Proyecto Fin de Carrera | 107


• MIComponente. Encapsula la metainformación asociada a un componente.
Proprociona métodos que permiten acceder y modificar la metainformación.

• MICompleta. Metainformación enviada por el ServidorMetainformación cuando una


aplicación cliente se identifica o cambia el rol asociado a un cliente.

• ServidorMetainformación. Se encuentra en las aplicaciones servidor. Se encarga


de la comunicación con las aplicaciones cliente.

Al arrancar el servidor, localiza el JavaSpace y queda a la “escucha” de solicitudes


procedentes de las aplicaciones cliente.

ServidorMetainformación contiene como atributo un objeto de la clase


AlmacenMetainformación, que le permite acceder a la metainformación
almacenada en el sistema.

La clase contiene también una cola de envío de eventos, donde el servidor


almacena los eventos a enviar. Una hebra se encargará de gestionar esta cola y
enviar los eventos en orden FIFO.

La clase cuenta con una serie de hebras:

# Hebra procesadora: es la encargada de procesar los eventos recibidos por el


servidor. Para cada posible tipo de evento recibido, se encarga de realizar la
acción asociada y, en caso de que sea necesario, agregar a la cola de envío
el(los) envento(s) de respuesta oportunos – que pueden ser para un único
destinatario o para todos las aplicaciones cliente–.
# Hebra de envío: Se encarga de enviar los eventos de la cola de envío.
# Hebra Desconexión Usuarios, se encarga de controlar los eventos KeepAlive
enviados por las aplicaciones cliente. Si la hebra detecta que han transcurrido
más de 60 segundos desde que un usuario envió el evento KeepAlive, el

Proyecto Fin de Carrera | 108


servidor considerará que el usuario se ha desconectado y lo eliminará de la lista
de usuarios activos, difundiendo un evento a todas las aplicaciones cliente con
la información de la desconexión del usuario.

• DialogoMetainformación2. Mediante este diálgo es posible modifcar la


meteinformación del sistema de forma totalmente gráfica: permite agregar,
modificar y eliminar usuarios o roles, agregar nuevos roles permitidos a un usuario
determinado, modificar los permisos de acceso de un usuario o rol sobre un
componente determinado, etc.

Una vez realizados los cambios que el usuario considere oportunos, los cambios
realizados en la metainformación serán difundidos por el sistema al resto de
clientes, si procede, y almacenados de forma permanente en el repositorio de
datos del sistema.

Ilustración 51: Ventana del diálogo de


metainformación

• PanelMetainformación. Panel Principal de DialogoMetainformación. Se trata de un


panel con pestañas.

2 Sólo se puede acceder a este diálogo si el usuario es administrado.

Proyecto Fin de Carrera | 109


Ilustración 52: Diagrama de clases del subsistema de gestión de metainformación

Proyecto Fin de Carrera | 110


7.1.4 Gestión de la metainformación de ficheros

El objetivo este subsistema es proporcionar la funcionalidad necesaria para que la


metainformación relativa a las distas aplicaciones (usuarios y roles permitidos, permisos
para los componentes, información de usuarios –como la lista de los roles permitidos
para un usuario–, usuarios conectados en un determinado momento, etc.) pueda ser
distribuida por el sistema a partir de la información almacenada en el repositorio de datos.
Así mismo, este subsistema también se encarga de realizar las comprobaciones
necesarias para garantizar que se cumplen las restricciones de acceso a las aplicaciones
y/o componentes. Por otro lado, el subsistema también proporcionará un mecanismo que
permita la modificación de la metainformación del sistema de forma gráfica. En la
siguiente figura se muestra el funcionamiento básico de este subsistema3:

En él, podemos observar


cómo se realiza el
intercambio del tipo de
información especificada
anteriormente:

! Cada vez que una


aplicación cliente
necesita de algún
tipo de información
acerca de los
Ilustración 53: Esquema arquitectónico del subsistema documentos
compartidos (permisos de acceso, tipo de fichero, ...), el Componente en cuestión
envía un mensaje al Dconector.

3 A pesar de estar incluidos en el diagrama, las clases GestoFicherosBD y ConcectorBD, estas clases no serán
especificadas en este punto.

Proyecto Fin de Carrera | 111


! El Dconector, a su vez, envía otro mensaje al Cliente Ficheros.

! El Cliente de Metainformación, envía un evento al JavaSpace con destino al


Servidor de Metainformación.

! El servidor recibe el evento y, en función del tipo de información requerida


procederá de la siguiente forma:
# Si dispone de la información de forma inmediata, responde al cliente mediante
un nuevo evento escrito en el JavaSpace
# Si no dispone de esa información, desplaza la consulta a la capa inferior, hasta
llegar como máximo a la Base de Datos. Una vez obtenida la información, ésta
rehace su camino hasta llegar de nuevo al Servidor, que responde al cliente
mediante un nuevo evento escrito en el JavaSpace

! El cliente lee el evento del JavaSpace, y devuelve la información al Dconector, que


a su vez la devuelve al componente.

! El componente realiza las acciones necesarias de acuerdo con la información


recibida.

Obviamente, el proceso anterior también puede extenderse a la modificación de


información (cambio de rol de un usuario determinado, por ejemplo).

Además de los elementos involucrados en el anterior esquema, en este subsistema se


incluyen una clase que permite representar la metainformación de un documento –tipo de
documento, dueño, permisos de acceso, localización, etc. –.

Por otro lado, las clases involucradas en este subsistema incluyen mecanismos de
detección y recuperación de errores (servidores caídos, clientes colgados, etc.), lo que
redunda en la fiabilidad y robustez del sistema.

Proyecto Fin de Carrera | 112


Clases involucradas

• ClienteFicheros. Se encuentra en las aplicaciones cliente. Se encarga de la


comunicación con el servidor de ficheros.

Al arrancar una aplicación cliente, se encarga de gestionar la sincronización del


usuario con el servidor de ficheros, dejando bloqueada la aplicación hasta que ésta
no se halla realizado con éxito.

Esta clase incluye un mecanismo de detección de error que permite que si se


produce algún fallo a la hora de la conexión con el servidor, la aplicación no puede
continuar con su ejecución.

Con el objetivo de garantizar la correcta sincronización a la hora de localizar el


JavaSpace, la clase incorpora un monitor que garantiza que no se realiza ninguna
actividad hasta que se halla tenido lugar la correcta sincronización con el servidor.
Este monitor también proporciona la funcionalidad necesario para comprobar si la
sincronización se ha llevado a cabo con éxito.

Ilustración 54: Diagrama de estados para


el monitor

Proyecto Fin de Carrera | 113


La clase cuenta con una serie de hebras:

# Hebra localizadora: es la encarga de localizar el JavaSpace. Una vez


localizado, notifica esta condición haciendo uso del monitor.
# Hebra detectora de error: controla los posibles errores que podrían producirse
durante la localización del JavaSpace, si transcurrido un tiempo prudencial no
se ha localizado el JavaSpace, se indicará la condición de error y la aplicación
terminará. El funcionamiento es bien sencillo: la hebra se duerme un tiempo
establecido, transcurrido el cual comprueba si se ha localizado el JavaSpace, si
esto es así, termina la hebra; en caso contrario, se notifica el error mediante el
Monitor.
# Hebra KeepAlive, se encarga de garantizar que el Servidor es consciente de
que el usuario sigue conectado. Envía un evento KeepAlive al servidor de
ficheros cada 30 segundos.
# Hebra Recolectora: es la responsable de gestionar los eventos recibidos por el
cliente; estos eventos serán enviados por el Servidor de Metainformación para
indicar cambios en la metainformación del sistema, siendo el cliente de
metainformación el encargado de difundir estos cambios entre los componentes
de la aplicación.

Esta clase incluye una serie de método que permiten acceder a la metainformación
de los documentos compartidos y modificarla. Algunos de los métodos más
importantes son:

Proyecto Fin de Carrera | 114


borrarFichero(MIDocumento f, java.lang.String aplicación): void

Envía un evento al servidor de Ficheros para que este elimine un fichero (su metainformacion y el fichero
físico)
existeFichero(java.lang.String path, java.lang.String aplicación):MIDocumento

Comprueba si existe un determinado fichero


generarVersion(MIDocumento doc, java.lang.String path) :void

Genera una nueva version de un fichero ya existente


getArbolDoc():DefaultMutableTreeNode

Obtiene el arbol de documentos asociado al usuario (con el rol especificado)


inicializar():void

Inicializa el cliente enviando una solicitud de sincronizacion al servidor de Metainformacion


insertarNuevoFichero(MIDocumento f, java.lang.String aplicación):MIDocumento

Envía un evento al servidor de Ficheros para que este agrege un fichero


modificarFichero(MIDocumento f, java.lang.String aplicacion):void

Modifica la metainformacion de un fichero


static ClienteFicheros obtenerClienteFicheros()

Método estático que devuelve el cliente de ficheros que se esta utilizando en este momento.

Tabla 7.1: Métodos públicos de la clase ClienteFicheros

• MIDocumento. Encapsula la metainformación asociada a un documento (o


carpeta):

# nombre: nombre del documento.


# id_documento: identificador unívoco del documento.
# es_directorio: indica si el documentos es un directorio.
# permisos: permisos asociados al documento.
# usuario: usuario propietario del documento.
# rol: rol asociado al documento.
# padre: identificador de la carpeta que contiene el documento.
# ruta_local: ruta del documento con respecto al sistema de archivos virtual.
# tipo: tipo del fichero.
# mensaje: mensaje asociado al documento.

Proyecto Fin de Carrera | 115


Así mismo, la clase tiene una serie de métodos que permiten recuperar y modificar
los campos anteriormente indicados.

• ServidorFicheros. Se encuentra en las aplicaciones servidor. Se encarga de la


comunicación con las aplicaciones cliente.

Al arrancar el servidor, localiza el JavaSpace y queda a la “escucha” de solicitudes


procedentes de las aplicaciones cliente.

Cada vez que una aplicación cliente inicia la sincronización con el servidor de
ficheros, éste envía al cliente la metainformación del conjunto de documentos y
carpetas para las cuales el usuario tiene, como mínimo, permiso de lectura
recuperadas de la base de datos. La forma en la que se envían estos datos es la
de un árbol en la cual la raíz es el directorio raíz (/), las hojas los documentos y los
nodos intermedios las carpetas. También en este mismo mensaje, el servidor
facilita la dirección IP y el puerto donde estará a la espera de solicitudes de
documentos vía RMI.

ServidorFicheros se comunica con la base de datos (con el objetivo de


recuperar/almecenar información relativa a los ficheros) mediante la clase
GestorFicherosBD.

La clase contiene también una cola de envío de eventos, donde el servidor


almacena los eventos a enviar. Una hebra se encargará de gestionar esta cola y
enviar los eventos en orden FIFO.

La clase cuenta con una serie de hebras:

# Hebra procesadora: es la encargada de procesar los eventos recibidos por el


servidor. Para cada posible tipo de evento recibido, se encarga de realizar la
acción asociada y, en caso de que sea necesario, agregar a la cola de envío
el(los) envento(s) de respuesta oportunos – que pueden ser para un único

Proyecto Fin de Carrera | 116


destinatario o para todos las aplicaciones cliente–.
# Hebra de envío: Se encarga de enviar los eventos de la cola de envío.
# Hebra Desconexión Usuarios, se encarga de controlar los eventos KeepAlive
enviados por las aplicaciones cliente. Si la hebra detecta que han transcurrido
más de 60 segundos desde que un usuario envió el evento KeepAlive, el
servidor considerará que el usuario se ha desconectado y lo eliminará de la lista
de usuarios activos, difundiendo un evento a todas las aplicaciones cliente con
la información de la desconexión del usuario.

• DnodeEvent. Evento que se envía cuando un cliente quiere sincronizarse con el


servidor de ficheros. Cuando el servidor recibe uno de estos eventos responde al
usuario, envía un evento de respuesta en el que se incluye el árbol de documentos.

• DfileEvent. Evento utilizado para la comunicación ordinaria entre ClienteFichero y


ServidorFicheros. El envío de este tipo de eventos permite a la aplicación cliente
modificar al metainformación de los documentos (cambiar permisos, cambiar
nombre, mover ficheros de una carpeta a otra) en el servidor. Además, todos los
cambios realizados serán, si es pertinente, difundidos por el servidor al resto de
aplicaciones conectadas al sistema en ese momento –si cambiamos los permisos
de acceso a un fichero, estos cambios se difundirán por el sistema, por ejemplo–.

Proyecto Fin de Carrera | 117


Diagrama de clases

Ilustración 55: Diagrama de clases del subsistema de gestión de metainformación de ficheros

Proyecto Fin de Carrera | 118


7.1.5. Subsistema de transmisión de datos

Se implementará un subsistema dedicado en exclusiva a la transmisión de datos (que no


sean eventos) entre usuarios. Éste subsistema permitirá transmitir ficheros completos o el
estado del editor compartido mediante una conexión par a par entre usuarios.

Cuando la aplicación cliente requiere realizar algunas de éstas operaciones, éste


subsistema entra en juego mediante dos clases fundamentales: Transfer y TransferP2P.
Ambas clases hacen uso de la tecnología RMI para la transferencia de datos.

Debido al uso de la tecnología RMI, será necesaria la creación de un interfaz que herede
de Remote y una clase que implemente ésta interfaz y herede de UnicastRemoteObject.

Tantos las clases anteriores como las interfaces creadas se explicarán a continuación.

Métodos remotos para la transferencia de datos (TransmisorFicheros y


TransferenciaFichero)

Se creará una interfaz Java llamada TransmisorFicheros que herede de Remote y que
implemente métodos para realizar las siguientes operaciones:

• Obtener un objeto de la clase Documento mediante el path del fichero en el


sistema. Se deberá usar un parámetro específico para indicar si queremos
interpretar en fichero como texto aunque no esté soportado.
• Obtener los bytes que forman un fichero dado por su path en el sistema.
• Obtener los bytes que forman un fichero dado por su path en la máquina que lo
almacena.
• Enviar los bytes que forman un fichero y su path en el sistema.
• Enviar los bytes que forman un fichero dado y su path en la máquina que lo
almacena.

Proyecto Fin de Carrera | 119


• Enviar un objeto de la clase Documento.

El path de los ficheros será con respecto al directorio base de donde los almacene
físicamente el servidor de ficheros. Por ejemplo, si los ficheros se almacenan en el path
“/Data”, entonces, se realizará una traducción del path de los ficheros de “/” a “/Data”.

Una vez definida ésta interfaz, la implementaremos en la clase TransferenciaFichero.

Métodos remotos para la transferencia de datos mediante P2P


(TransmisorFicherosP2P y TransferenciaFicheroP2P)

Se creará una interfaz Java llamada TransmisorFicherosP2P que herede de Remote y


que implemente un método para poder recibir un Documento.

Una vez definida ésta interfaz, la implementaremos en la clase TransferenciaFicheroP2P.


Ésta clase tendrá un objeto de la clase Documento como atributo. Éste objeto será el
recibido en el otro extremo de la transferencia.

Transferencia de datos (Transfer)

Clase que se encarga de la transmisión de objetos de la clase Documento y de archivos


entre las aplicaciones cliente y el servidor de ficheros.

Esta clase presenta un comportamiento dual:

1. Por un lado, permite que una aplicación se convierta en un servidor RMI, con la
sola invocación del método estático establecerServidor(int). Este método registra
un objeto de la clase TransferenciaFichero, que será el objeto que reciba las
peticiones de los clientes. El proceso seguido es sencillo: crea el registro local, crea
un nuevo objeto TransferenciaFichero y lo registra mendiante el método bind().

Proyecto Fin de Carrera | 120


2. Por otro lado, instanciando un objeto de la clase Transfer utilizando su constructor
Transfer(String ip_destino, String fichero, boolean forzar_texto), podemos:
a) Enviar un fichero al servidor mediante el método sendFile(byte[])
b) Guardar los cambios realizados en un documento en el servidor:
sendDocumento(Documento)
c) Recibir el contenido de un fichero para su posterior almacenamiento local:
receiveFileBytes()
d) Recibir un documento desde el servidor: receiveDocumento(boolean)

Transferencia de datos mediante P2P (TransferP2P)

Clase que se encarga de la transmisión de objetos de la clase Documento y de archivos


entre las aplicaciones cliente.

Esta clase presenta un comportamiento dual:

1. Por un lado, permite que una aplicación se convierta en un servidor RMI, con la
sola invocación del método estático establecerServidor(int puerto_escucha). Este
método registra un objeto de la clase TransferenciaFichero, que será el objeto que
reciba las peticiones de los clientes. El proceso seguido es sencillo: crea el registro
local, crea un nuevo objeto TransferenciaFicheroP2P y lo registra mediante el
método bind(). A diferencia de la Transfer, también se permite para y re-iniciar el
servidor, mediante los métodos estáticos pararHebra() y establecerServidor(int
puerto, Documento aCompartir). Cada vez que una aplicación cliente inicia un
servidor se le asigna un identificador, que será utilizado por las aplicaciones cliente
para identificarla.

2. Por otro lado, instanciando un objeto de la clase TransferP2P utilizando su


constructor Transfer(String ip_destino, int id, int puerto), podemos:
a) Recibir un documento desde el servidor: receiveDocumento()

Proyecto Fin de Carrera | 121


Diagrama UML del subsistema

Ilustración 56: Diagrama de clases para el subsistema de Transmisión de datos

Proyecto Fin de Carrera | 122


7.2. Subsistemas específicos para la creación de la plataforma

Los subsistemas descritos a lo largo de ésta sección estarán dedicados a la creación de


la plataforma a implementar para crear la aplicación final.

7.2.1. Subsistema de Gestión de Documentos

Uno de los objetivos principales que se persiguen en este desarrollo es la gestión de


documentos compartidos entre los distintos usuarios que utilizan el sistema colaborativo,
de manera que puedan acceder a ellos desde sus máquinas locales de forma
transparente.

El esquema utilizado para alcanzar el anterior objetivo es el siguiente:

• El almacenamiento de los documentos compartidos se realizará de forma


centralizada: se almacenarán en la máquina, fija, en la que se ejecutará el servidor,
formando parte del sistema de archivos. En concreto se almacenarán en una
carpeta en concreto, que será tomada como directorio raiz (/) del sistema de
ficheros virtual.

• Cada vez que un cliente solicite el acceso a un fichero concreto a través de su ruta
en el sistema de archivos virtual, el servidor de ficheros realizará una traducción
automática de esa ruta a la ruta correspondiente en su sistema de ficheros local.
Por ejemplo, si el cliente solicita el documento /Publico/Informes/Informe0.pdf y en
la máquina del servidor la carpeta donde se almacenan los datos es /DATA, el
servidor realizaría la siguiente traducción: /DATA/Publico/Informes/Informe0.pdf

Proyecto Fin de Carrera | 123


• Paralelament
e, el servidor
de ficheros
almacena en
una Base de
Datos toda la

Ilustración 57: Esquema arquitectónico del subsistema


metainformación de los ficheros (propietarios, carpeta que lo contiene, etc.). El
servidor se encargará en todo momento de garantizar la consistencia entre los
documentos almacenados y la información acerca de éstos guardada en la base de
datos. La estructura elegida para representar la metainformación de un documento
sería la siguiente:

# id_documento: identificador unívoco del documento. Cada vez que se añade un


nuevo documento al sistema se le asigna de forma automática un identificador.
# nombre: nombre del documento.

Proyecto Fin de Carrera | 124


# es_directorio: indica si el documentos es un directorio. Sólo si es un directorio
puede contener otros documentos.
# permisos: permisos asociados al documento. La estructura de los permisos
sigue un modelo Unix-like simplificado:

% Existen dos niveles de acceso:


$ Lectura: este permiso permite visualizar los documentos, anotarlos y
guardar copias locales de él. Cuando se trata de una carpeta, el permiso
de lectura también se asimila a un permiso de paso.
$ Escritura: este permiso permite eliminar el documento, mover el
documento de lugar y modificar su metainformación (nombre, tipo,
permisos, etc.)
% Exisen tres “subgrupos” de permisos:
$ Usuario: indica los permisos que tiene sobre el documento el usuario
propietario.
$ Rol: indica los permisos que tienen sobre el documento los usuarios que
desempeñan el rol asociado al documento.
$ Otros: indica los permisos que se aplican a los usuarios que no encajan
en ninguno de los dos grupos anteriores.
La codificación de los permisos se realiza mediante una cadena de texto de
longitud seis de la siguiente forma:
% Las dos primeras posiciones se refieren a los permisos del usuario. La
primera de ellas codifica los permisos de lectura y la segunda los de
escritura.
% Las dos posiciones intermedias se refieren a los permisos del rol. La primera
de ellas codifica los permisos de lectura y la segunda los de escritura.
% Las dos últimas posiciones se refieren a otros. La primera de ellas codifica
los permisos de lectura y la segunda los de escritura.
Un carácter '-' en una posición indica que no se poseen los permisos asociados
a esa posición. Un carácter 'r' en una posición de permiso de lectura indica que
se posee el permiso de lectura. Un carácter 'w' en una posición de permiso de
escritura indica que se posee el permiso de escritura sobre el documento.

Proyecto Fin de Carrera | 125


Cualquier otro carácter, será tomado como '-'.

Por ejemplo, si tenemos los permisos “rwr---” asociados a un documento creado


por el usuario Pepe bajo rol Empleado, el significado de los permisos sería que:
% Pepe puede leer y escribir el documento.
% Los usuarios bajo el rol Empleado pueden leer el documento, pero no
escribirlo.
% El resto de usuarios no puede acceder al documento.

# usuario: usuario propietario del documento.


# rol: rol asociado al documento.
# padre: identificador de la carpeta que contiene el documento.
# ruta_local: ruta del documento con respecto al sistema de archivos virtual.
# tipo: tipo del fichero. Puede ser una imagen un documentos de texto, un PDF,
un mesaje electrónico o cualquier otro tipo de fichero. El tipo de fichero resultará
esencial a la hora de determinar que filtro aplicar a la hora de abrir un
documento4.
# mensaje: mensaje asociado al documento.

Modelo para los documentos (clase Documento)


La clase Documento permite la visualización de los documentos por parte de los usuarios.
Un objeto de la clase documento está formada por un conjunto de páginas ordenadas.
Cada página a su vez tiene asociada una lista de anotaciones realizadas sobre la página
en cuestión (ver diagrama de clases inferior).

La clase Documento proporciona métodos para acceder a las página y anotaciones del
documentos, crear documentos a partir de ficheros, imprimir el contenido de los
documentos, guardar los comentarios realizados sobre un documento, etc.

La clase Documento contiene una lista estática de filtros (DocumentFilter), que son los
que determinan que tipos de ficheros pueden ser abiertos (ver el siguiente punto). Una de

4 Ver punto donde se explica de forma detallada la clase Documento y los filtros aplicados a los documentos.

Proyecto Fin de Carrera | 126


las principales ventajas de este esquema es que permite que se añadan de forma
dinámica nuevos filtros a la lista, permitiendo que se amplíen el tipo de documentos
soportados en tiempo de ejecución.

Un ejemplo de la utilidad del agregado dinámico de filtros podría estar en los plugins:
utilizando un plugin que agregue nuevo filtros a al lista de la clase Documento podemos
soportar nuevos documentos si necesidad de retocar el código de la aplicación.

Filtros para documentos (DocumentFilter)

La interfaz Filtro, permite la definición de filtros para abrir documentos: un filtro es una
clase que genera un objeto de la clase Documento a partir de un fichero aplicando un
determinado renderizado sobre las imágenes que componen cada página del documento,
en función del tipo de fichero que sea.

Dicho de otra forma, un filtro es una clase que provee un determinado método cuyo
funcionamiento básico sería:

1. Se abre el fichero.
2. Se lee el contenido del fichero y se “pinta” sobre las imágenes que forman
las páginas del documento, de acuerdo con el tipo de fichero.
3. Se devuelve el documento creado.

Por ejemplo, un filtro de imágenes se limitará a abrir la imagen y asignarla a la imagen


correspondiente a la primera y única página del documento; por contra, un filtro de
documentos de texto plano “dibujaría” el texto en las imágenes correspondientes,
incrementando el número de páginas del documento hasta que se haya completado el
dibujo de todo el texto.

Los métodos que deben implementar las clases que implementes este interfaz serían:

• getDocumento(path, usuario, rol):Documento. Genera el objeto Documento

Proyecto Fin de Carrera | 127


asociado al fichero que se encuentra en la ruta path.
• isSuported(extensión):boolean. Indica si una determinada extensión es soportada
por el filtro.

Dentro del Framework desarrollado se han incluido los siguientes cuatro filtros:

1. Filtro de imágenes (IMGFilter): su funcionamiento básico es el descrito


anteriormente.

2. Filtro de documentos de texto plano (TXTFilter): su funcionamiento básico es


el descrito anteriormente.

3. Filtro de mensajes de correo electrónico (MSGFilter): en esencia el


comportamiento es idéntico al descrito para los documentos de texto.

4. Filtro para documentos PDF (PDFFilter): utiliza la funcionalidad


proporcionada por la librería PDFRenderer.

Modelado de una página

Un objeto de la clase Página representa una página de un documento. En realidad, cada


página del documento se corresponde con una imagen. Cada página incluye una lista de
anotaciones realizadas sobre la página.

La clase provee de una serie de métodos para acceder y modificar sus atributos.

Modelado de una anotación en un documento

Un objeto de la clase Anotación representa una anotación realizada sobre un documento


por un usuario. Para cada anotación se almacenan el usuario que la realizó, el rol bajo el
que la hizo y la fecha y hora.

Proyecto Fin de Carrera | 128


Asociada a cada anotación, está su representación gráfica en forma de un objeto de la
clase Figura que puede representar un texto, un rectángulo, una línea, un óvalo o un trazo
a mano alzada.

La clase Anotación proporciona métodos que permiten acceder a sus atributos y modificar
sus valores.

Funcionamiento conjunto:

Cuando un usuario solicita un documento el procedimiento llevado a cabo por el


servidor será el siguiente:

1 El servidor recibe la solicitud visualización (o apertura) del documento.


2 El servidor realiza la transformación de la ruta del fichero del sistema de archivos
virtual a su sistema de archivos.
3 El servidor crea un nuevo documento a partir del método estático openDocument()
de la clase Documento:
3.1 La clase documento comprueba el tipo de documento a abrir. Si no está
soportado por ningún filtro el método devuelve null.
3.2 Si el tipo está soportado, el método llama al método openDocument() del
primer filtro que soporte el tipo del fichero a abrir.
3.3 Busca el fichero de anotaciones asociado al documento y si lo encuentra,
agrega las anotaciones al documento.
3.4 Devuelve el documento.
4 El sistema envía, vía RMI, el documento devuelto por openDocument() al cliente
que lo solicitó.

Proyecto Fin de Carrera | 129


Diagrama de Clases

Ilustración 58: Diagrama de clases del subsistema Documento

Proyecto Fin de Carrera | 130


7.2.2. Subsistema de Edición Compartida de Documentos

Uno de los objetivos que se persiguen con la implementación del Framework es el


proporcionar el soporte necesario para la anotación compartida de documentos.

La funcionalidad de este subsistema se apoya en otros cinco subsistema que le ofrecen


sus servicios:

• Subsistema de Componentes. La clase DILienzo incluída en este subsitema


proporciona la funcionalidad necesario para la visualización de los documentos y
su anotación.
• Subsistema de Gestión de Metainformación de Ficheros: este subsistema
proporciona al módulo de edición compartida de documentos las facilidades de
acceso y modificación de la metainformación de los documentos.
• Subsistema de Gestión Documentos. Proporciona clases que permiten generar una
visualización a partir de un fichero, gestionar sus páginas, realizar anotaciones, etc.
• Subsistema de Gestión de Eventos. Proporciona mecanismos que permiten la
sincronización de las anotación del documento.
• Subsistema de Transmisión de datos. Permite la recepción y envío de documentos
a través de la red, utilizando para ello RMI.

En el proceso seguido a la hora de anotar un documento se distinguen dos fases bien


diferenciadas:

1. Apertura del documento. En este primer paso, se recupera el documento que se


quiere anotar. Pueden darse dos casos:

a) Ningún otro usuario tiene el documento abierto. En ese caso se recupera el


documento directamente del servidor de ficheros.
b) Hay, como mínimo, otro usuario con el documento abierto. En este caso es

Proyecto Fin de Carrera | 131


necesario recuperar el documento desde alguno de los usuarios que lo están
editando. La razón de que haya que recuperarlo desde otro usuario y no desde
el servidor es la de obtener la última versión del documento, con las
anotaciones realizadas por los otros usuarios y que no hayan sido todavía
guardadas. Si se cargase el documento desde el servidor, nos encontraríamos
con una copia del documento en un estado inconsistente con el resto de copias
abiertas.

2. Anotación del documento. En esta fase se presenta al usuario una visualización del
documento y se le permite desplazarse por el documento, anotarlo, eliminar
anotaciones, guardar los cambios realizados en el documento, etc.

Fase 1: Apertura del documento

Durante el proceso de apertura de un documento para su edición hay que garantizar que
el documento recibido sea consistente con la última copia modificada de éste. Dicho en
otras palabras, la copia del documento que tenemos que recibir debe de ser aquella que
refleje la últimas modificaciones realizadas sobre el documento, aunque éstas no hayan
sido guardas.

Para garantizar que se cumple lo expresado en el párrafo anterior, debemos de controlar


en todo momento que documentos están abiertos en cada momento y qué usuarios los
han abierto. Esta tarea de control de documentos abiertos se realiza mediante la escritura
de tokens (de la clase Deventos.tokens.TokenFichero) en el JavaSpace.

Para cada documento abierto en el sistema, se escribe un token en el JavaSpace. En este


token se incluye una lista con los usuarios que en ese momento se encuentran editando el
documento.

Además de la lista de usuarios, también se incluye el estado del token, que puede ser
bloqueado o desbloqueado. Cuando el token está en estado bloqueado, significa que hay
algún cliente abriendo el documento y que los eventos relacionados con las anotaciones

Proyecto Fin de Carrera | 132


deben de esperar a que este esté desbloqueado.

La implementación del token será muy parecida a la de un evento cualquiera del sistema:
Será una implementación de la interfaz “Entry” para permitir su escritura en JavaSpaces.

En el siguiente diagrama de clases podemos observar la estructura de la clase


TokenFichero

Ilustración 59: Diagrama de clases para TokenFichero

El esquema de uso de TokenFichero sería el siguiente:

1. Apertura de un documento.

a) Si el token asociado al documento no existe, se crea un un nuevo TokenFichero


asociado al documento y se escribe en el JavaSpace indicando que se
encuentra bloqueado5. Se solicita el envío del documento al servidor de
ficheros. Una vez recibido, y si no ha habido errores, se recupera el token se
cambia su estado a desbloqueado y se reescribe.
5 Se reescribe con estado bloqueado para evitar que, si otra aplicación intenta abrir el documento y no
encuentra el token, cree un nuevo token, pudiendo encontrarnos con que tenemos más de un token para
un único documento.

Proyecto Fin de Carrera | 133


b) Si existe el token, se retira del JavaSpace, se marca como bloqueado 1 y se
envía un evento de sincronización del documento. Cuando otro cliente recibe
este evento, envía un evento de respuesta de sincronización conteniendo su
dirección IP y el puerto en el cual se encuentra esperando las solicitud del
documento. La aplicación solicitante recibe la respuesta y descarga el
documento desde la aplicación que ha respondido a su solicitud. Una vez
recibido el fichero correctamente recupera el token, lo marca como
desbloqueado, incluye su nombre en la lista de editores y lo reescribe en el
JavaSpace.

De forma gráfica, el proceso sería el descrito por los diagramas siguientes:

Ilustración 60: Esquema de funcionamiento del mecanismos de


apertura de documentos

Proyecto Fin de Carrera | 134


Ilustración 61: Esquema de funcionamiento del mecanismos de apertura de
documentos

2. Modificación del documento (nueva anotación, deshacer última acciónm etc,). Un


cliente solo enviará los eventos de modificación sobre un documento cuando posea
el token y este esté marcado como no bloqueado. Si no lo posee o este está
bloqueado (alguna otra aplicación está intentando abrir ese documento), éstos se
almacenarán en una cola de envío para su posterior envío.

3. Cierre de un documento: el usurio retira el token del JavaSpace y se elimina de la


lista de editores. Si tras eliminarse la lista está vacía, el token se elimina. En caso
contrario vuelve a escribirse en el JavaSpace.

El uso de éste token se realizará principalmente dentro del subsistema de edición


compartida de documentos, el cuál se detalla en secciones posteriores

Proyecto Fin de Carrera | 135


Fase 2: Anotación del documento

Una vez abierto el documento, este le será presentado al usuario en una ventana dividida
en tres secciones: una barra de controles, el lienzo donde se muestra el documento y una
barra de estado en la que se indica la página actual y que nos permite cambiar de página.

El aspecto del editor sería el siguiente:

Ilustración 62: Aspecto del editor

De forma más detallada:

• Barra de controles:
La barra de controles consta de una barra de herramientas conteniendo una serie
de botones que nos permiten acceder a la anotación del documento. De izquierda a
derecha tenemos:
# Abrir: permite abrir un nuevo fichero.
# Guardar: guarda las modificaciones realizadas en el documento en el servidor.

Proyecto Fin de Carrera | 136


# Guardar localmente: guarda una copia local del documento.
# Imprimir: imprime el documento.
# Deshacer: deshace la última acción realizada.
# Rehacer: rehace la ultima acción desecha.
# Anotación anterior: selecciona la anotación anterior a la actualmente
seleccionada. Si no está seleccionada ninguna, selecciona la última de esa
página.
# Anotación siguiente: selecciona la anotación siguiente a la actualmente
seleccionada. Si no está seleccionada ninguna, selecciona la primera de esa
página.
# Herramienta de selección: activa la selección de las anotaciones vía click sobre
ellas. Si ya esta activada pulsando otra vez sobre el botón se desactiva.
# Eliminar Anotación: elimina la acción seleccionada. Si no hay anotación
seleccionada no se hace nada.
# Pincel: lista desplegable que nos permite escoger el pincel o tipo de trazo con el
que queremos realizar las anotaciones.

Ilustración 63: Barra de controles


# Colores: muestra un diálogo de selección de colores que nos permite escoger el
color de las anotaciones.

• Barra de estado:

Ilustración 64: Barra de estado

La barra de estado se compone de cuatro elemento:

Proyecto Fin de Carrera | 137


• Dos botones de desplazamiento.
# Atrás: Retrocede hasta la página anterior.
# Adelante: Avanza a la siguiente página del documento
• Un campo de texto que muestra el número de la página del documento en la
que nos encontramos y que nos permite introducir el número de página para
desplazarnos hasta ella (obviamente, si la página no existe no se produce tal
desplazamiento y el número de página mostrado se mantiene en su valor
original)
• Una etiqueta que muestra el número de páginas del documento.

• Lienzo:
El lienzo nos permite realizar anotaciones sobre los documentos, borrarlas, etc. y
mediante el envío de eventos distribuir estas acciones al resto de aplicaciones que
también se encuentren editando ese documento.
Para realizar una anotación sobre un documento ya abierto no tenemos más que:
1. Desplazarnos hasta la página deseada utilizando la barra de estado.
2. Seleccionar el tipo de anotación y el color.
3. Arrastrar el ratón sobre el lienzo.

Para representar de forma gráfica las anotaciones, se ha utilizado una jerarquía de


clases que permiten representar las figuras correspondientes a las anotaciones
(texto, rectángulo, línea, etc.).

Ilustración 65: Diagrama de clases para las figuras

Proyecto Fin de Carrera | 138


El diagrama de clases correspondiente sería el siguiente:
En la siguiente tabla tenemos la especificación de los métodos asociados a la clase
Figura:

abstract void dibujar(java.awt.Graphics g)

Dibuja la figura el un objeto graphics


java.awt.Color getColor()

Consulta el color de la figura


int getX()

Consulta la coordena x de la figura


int getY()

Consulta la coordenada y de la figura


abstract boolean pertenece(int x, int y)

Comprueba si un determinado punto pertenece a la figura


void setColor(java.awt.Color color)

Establece el color de la figura


void setX(int x)

Actualiza el valor de la coordenada x de la esquina superior izquierda de la figura


void setY(int y)

Actualiza el valor de la coordenada y de la esquina superior izquierda de la figura

Tabla 7.2: Métodos públicos de la clase abstracta Figura

7.2.3. Subsistema de plugins

La aplicación cliente tendrá, además de gestión de documentos compartidos y sistemas


para la comunicación y la coordinación, un subsistema completo dedicado a la creación
de plugins para ésta. Éste subsistema se encargará de cargar dinámicamente los plugins
desde un directorio, actualizar convenientemente la lista de plugins disponible para la
aplicación cliente, modificar dinámicamente el classpath de Java para agregar las clases
asociadas a un plugin concreto y gestionar mediante eventos el hecho de que se
encuentre una versión nueva de un plugin de forma local a alguna de las aplicaciones
cliente disponibles en el sistema compartido. Ésto último proporcionará un sistema de
gestión de versiones para los plugins.

Proyecto Fin de Carrera | 139


Los plugins serán una de las partes fundamentales del sistema, ya que permitirán
adaptarlo a las necesidades concretas de cada usuario mediante sencillas técnicas de
adaptación de aplicaciones antiguas o de creación de otras nuevas. En cuanto a éste
último punto se dedica el apéndice completo Manual del desarrollador, que se encarga de
mostrar el proceso de desarrollo de un plugin.

Hay que destacar el hecho de que se proporcionarán tres plugins por defecto en el
sistema, los cuales proporcionan características que son fundamentales para éste: Un
chat completo (con videoconferencia), un gestor de plugins (que permita agregar o
eliminar plugins y alguna tarea de configuración básica) y una pizarra para dibujo
compartido (una versión reducida del editor de documentos que se verá en secciones
posteriores).

A lo largo de las sucesivas secciones se podrá ver cuales serán los mecanismos que se
usarán para el desarrollo del subsistema de plugins, así como de los plugins
anteriormente expuestos.

Clase abstracta para la implementación de plugins (DabstractPlugin)


Un plugin será considerado un componente gráfico como cualquier otro del sistema, por lo
que será una especialización de DcomponenteBase, que es el componente gráfico que
actuará como base para todos los demás (se podrá estudiar ésto con más profundidad en
la sección dedicada a los componentes gráficos).

La clase DabstractPlugin será una clase abstracta donde se establecerán los parámetros
fundamentales que deberá tener cualquier plugin, así como tres métodos a implementar
por el desarrollador (abstractos): init, start y stop.

Los parámetros fundamentales que tendrá cualquier plugin serán:

Proyecto Fin de Carrera | 140


• nombre. Nombre del plugin que se mostrará al usuario de la aplicación cliente.

• version. Versión del plugin. Solo tendrá sentido para cuando activemos el control
de versiones (se verá en secciones posteriores).

• jarFile. Nombre del fichero .jar que contendrá el plugin. Permitirá, si se activa el
control de versiones, que el sistema tenga conocimiento del fichero que se debe
transmitir al resto de clientes.

• versioningEnabled. Permitirá activar el control de versiones. Será un parámetro


opcional, puesto que por defecto se asignará a False.

• shouldShow. Permitirá exponer si el desarrollador desea que el plugin se muestre


por defecto al usuario de la aplicación cliente o no. Ésto es interesante cuando
creamos plugins que no tienen interfaz gráfica, es decir, que solo aportan
funcionalidad. Un ejemplo de ésto es un plugin que implementa un filtro nuevo para
un documento.

• categoria. Permitirá asignar una categoría al plugin. En la actual fase de desarrollo


del sistema no se utilizará, pero es muy interesante para que en un futuro se de
soporte a algún esquema de ordenación de plugins. Será un parámetro opcional,
puesto que por defecto si asignará a la categoría Otros. Las categorías que estarán
disponibles serán: Multimedia, Comunicación, Desarrollo, Edición, Ocio,
Información, Utilidades, Científico y Otros.

• descripción. Permitirá poner una descripción a un plugin. Será un parámetro


opcional, pero de cierta importancia de cara al usuario final, ya que la descripción
se mostrará como Tooltip al mostrar la lista de aplicaciones (plugins) disponibles en
la plataforma. Si no se asigna, el usuario final deberá ejecutar el plugin para saber
cuál es su cometido.

En cuanto a las operaciones abstractas que provee la clase DabstractPlugin, éstas se

Proyecto Fin de Carrera | 141


comentan a continuación:

• init. Será el método encargado de inicializar todos los parámetros específicos para
un plugin, así como los parámetros generales que sean opcionales. Deberá
llamarse desde el constructor de cualquier plugin implementado.

• start. Indicará que se debe realizar para ejecutar el plugin. Será el método que se
llame cuando el usuario final desee abrir un plugin en la aplicación cliente.

• stop. Indicará las operaciones a realizar cuando se descargue el plugin en el


sistema. Éste proceso solo se realizará cuando la aplicación cliente termine su
ejecución. Será interesante sobre todo para cuando se usen flujos de datos, para
cerrarlos correctamente. También puede ser interesante para “frenar” el cierre de la
aplicación cliente hasta que otro proceso termine, puesto que ésta no se cerrará
hasta que no se hayan realizado las llamadas a éste método para cada plugin del
sistema.

Como se puede observar, la adaptación de cualquier aplicación existente será trivial. La


creación de un plugin desde el principio se explicará con detalle en el manual del
desarrollador.

Modificación del classpath de Java de forma dinámica (ClassPathModifier)

Puesto que al iniciar la aplicación cliente se cargarán los plugins que estén disponibles
para ésta, será necesario modificar el classpath de java en tiempo de ejecución. Éste
proceso, que a priori puede resultar muy complejo tendrá una solución muy sencilla:
Buscar el método de Java encargado de realizar ésto e invocarlo en tiempo de ejecución.

El método más adecuado para realizar ésto en Java, tras un arduo proceso de
investigación, se ha determinado que es addURL, el cual es un método privado de la
clase URLClassLoader.

Proyecto Fin de Carrera | 142


Para solventar el hecho de que éste método sea privado se realizará lo siguiente:

• Se extraerá el método en forma de objeto desde la clase URLClassLoader


mediante una cadena que represente a su nombre (“addURL”). Ésto se realiza
mediante el método de la clase Class conocido como getDeclaredMethod.
• Se convertirá en público mediante el método setAccesible (con párametro true).
• Se invocará el método, tomando como parámetros un objeto de la clase
URLClassLoader y la clase a agregar al classpath (en forma de objeto del tipo URL
de Java).

La clase que realiza éste proceso se llamará ClassPathModifier y tendrá tres métodos
para agregar un fichero al classpath: Mediante una cadena de texto que represente el
path del fichero, mediante un objeto de tipo File y mediante un objeto de tipo URL.

Cargador de plugins para el sistema (DPluginLoader)

Se implementará una clase que permitirá la carga de los plugins que se encuentren
disponibles para la aplicación cliente. Los plugins serán una serie de ficheros con
extensión .jar que se encontrarán situados en la carpeta “plugin”, subcarpeta del directorio
donde se encuentre la aplicación cliente.

Se dispondrán de dos métodos:

• getPlugin. Dado el path de un fichero .jar que contenga un plugin, devolverá un


objeto de la clase DabstractPlugin. Para comprobar si el fichero contiene la
implementación de un plugin, se deberá comprobar, fichero a fichero, del interior
del fichero .jar, si alguno de ellos (con extensión .class) es subclase de
DabstractPlugin. El primero que encontremos lo usaremos para crear una nueva
instancia del objeto correspodiente al plugin. Todos los ficheros .jar que actúen
como parámetro de ésta clase serán agregados dinámicamente al classpath de
Java.

Proyecto Fin de Carrera | 143


• getAllPlugins. Permitirá obtener un vector de objetos de la clase DabstractPlugin
dado un directorio (en la aplicación cliente, éste directorio será “plugin”). Para
realizar ésta operación, se abrirá el directorio como si fuese un fichero mediante la
clase File de Java. A continuación se listará el contenido del directorio y se tomarán
aquellos ficheros que tengan extensión .jar. Para cada fichero se llamará al método
getPlugin, anteriormente descrito.

Contenedor de plugins del sistema (PluginContainer)

Se deberá implementar una clase que permita actuar de interfaz para la gestión de
plugins. Deberá mantener un listado de los plugins disponibles para el sistema, así como
permitir la inserción o eliminación de éstos. También permitirá métodos para hacer visible
o no un plugin concreto, u obtener algunas de sus características principales (sin tener
que acceder elemento a elemento de la colección, solo haciendo uso de su índice dentro
de ésta).

Puesto que el control de versiones implicará que la colección de plugins se actualice


constantemente, y ésto puede realizarse por múltiples hebras dentro del sistema, ésta
colección tendrá asociada un monitor para evitar conflictos en el acceso compartido.

El diagrama de estados del funcionamiento de las hebras que hacen uso del monitor que
controla la actualización dinámica de plugins se muestra a continuación.

Ilustración 66: Diagrama de estados para las


hebras que esperan la sincronización con
PluginContainer

Proyecto Fin de Carrera | 144


Gracias a ésta clase aplicaremos el patrón de diseño fachada (Façade) para los plugins:
Será la interfaz unificada que haga de intermediaria entre la aplicación cliente y el
conjunto de clases que accedan a los plugins de una forma más cercana al “bajo nivel”.
Control de versiones en plugins

El control de versiones de plugins supondrá el mayor esfuerzo a nivel de implementación


de la clase DabstractPlugin. Deberá ser en todo caso absolutamente transparente al
desarrollador de plugins. El desarrollador de plugins deberá, únicamente, asignar a True
el parámetro versioningEnabled del plugin que esté implementando. Si éste parámetro
está deshabilitado, entonces el proceso que se describe a continuación no se llevará a
cabo.

El proceso seguido por el sistema de control de versiones funcionará del siguiente modo:

• El constructor de la clase DabstractPlugin llamará a un método privado llamado


“register”. Esto obligará a que en la implementación de plugins será necesario
llamar en cada constructor al constructor de la superclase.

• El método register creará una hebra de procesamiento de eventos recibidos.


Además enviará un evento de registro de plugin (implementado en la clase
DpluginRegisterEvent). Éste evento contendrá el nombre, versión y nombre del
fichero .jar del plugin. Además, incluirá la dirección IP de la aplicación cliente local.
Ésta dirección IP permitirá realizar una posible transmisión entre aplicaciones
clientes mediante conexión par a par (peer to peer), para evitar que los datos
pasen a través de JavaSpaces, ya que ésto sobrecargaría demasiado éste servicio.

• Las hebras de procesamiento de Dabstractplugin en cada cliente recibirán el


evento anterior. Si alguno tiene una versión más avanzada, entonces solicitarán al
cliente que decida si debe instalar la nueva versión o quedarse con la que tiene.
Igualmente, si algún cliente tiene una versión anterior, se le pedirá al usuario que
decida si debe descargar el nuevo plugin o quedarse con el antiguo.

Proyecto Fin de Carrera | 145


• Si algún cliente decide actualizar un plugin, el cliente que tenga la versión más
actual lo transmitirá mediante una conexión par a par.

• Los plugins actualizados se cargarán de forma dinámica para que sea transparente
para el usuario. En algún caso, para que el funcionamiento sea el esperado, puede
ser necesaria una reinicialización de la aplicación cliente.

Debido al sistema de transmisión de ficheros, será estrictamente necesario, en caso de


activar el control de versiones, que asignemos un nombre correcto al fichero .jar que
contendrá el plugin.

Plugins para realizar cálculos paralelos

Puesto que todo el sistema hace uso de elementos de distribución de eventos, se deberá
hacer una base para la creación de plugins orientados a realizar cálculos paralelos,
haciendo uso de la infraestructura implementada. Debido al modelo seguido por el resto
del sistema, el modelo del sistema de cálculo paralelo será del tipo Maestro/Esclavos.

Para realizar ésto se deberán implementar los siguientes elementos:

• La base para el maestro. Ésta clase maestra se llamará “GenericMaster”. Será un


tipo especial de plugin (heredará de DabstractPlugin). Será una clase abstracta
donde se deberán implementar dos métodos protegidos: Uno para generar tareas y
otro para recopilarlas en un resultado. Los métodos abstractos de la clase
DabstractPlugin se implementarán en ésta clase.

• La clase que representará una tarea (TaskEntry) será un evento (heredará de


Devent) y será necesario implementar su método execute. Éste método será el
encargado de realizar el procesamiento necesario en cada esclavo. La clase
TaskEntry implementará la interfaz Command, la cuál permitirá enviar comandos
entre el maestro y los esclavos. Una vez terminado el procesamiento se enviará el
resultado al maestro.

Proyecto Fin de Carrera | 146


• La clase que representa un resultado (ResultEntry) será un evento que se enviará
desde cada esclavo hasta el maestro, para que éste realice lo necesario. El
resultado estará siempre modelado con una cadena de texto (un mensaje).

• La base para los esclavos. Ésta clase esclava se llamará “GenericWorker”. No se


podrá heredar de ésta clase (tendrá el modificador final en su definición), puesto
que todos los trabajadores actuarán de la misma forma: Le llegará una tarea , es
decir, un objeto de tipo TaskEntry, la ejecutarán llamando al método execute, y el
resultado lo enviarán al maestro mediante un objeto ResultEntry con un mensaje
específico.

• Una píldora venenosa (poison pill) para los esclavos que se implementará en la
clase PoisonPill. Ésto será un tipo de evento especial que hará que un esclavo
termine automáticamente de ejecutar sus tareas.

El siguiente diagrama de clases ilustra lo anteriormente descrito:

Proyecto Fin de Carrera | 147


Ilustración 67: Diagrama de clases para el subsistema CalculoParalelo

Debido a la amplitud de éste diagrama no será agregado al diagrama general del


subsistema de plugins que se mostrará en secciones posteriores.

Plugins por defecto (DchatPlugin, DmanagerPlugin y DwhiteBoardPlugin)

De forma predeterminada, se incluirán tres plugins que permitirán realizar tareas de


colaboración y comunicación que se han considerado básicas para el sistema: Un chat
con videoconferencia, un gestor de plugins y una pizarra para pintura colaborativa. El chat
y la pizarra harán uso de componentes gráficos implementados para éste sistema y
totalmente reutilizables. Éstos componentes se explicarán ampliamente en la sección
dedicada a componentes gráficos (beans). A continuación se muestra una descripción de
como deberá funcionar cada uno de éstos plugins.

• El chat con videoconferencia consistirá en un listado de usuarios, un panel donde

Proyecto Fin de Carrera | 148


se puedan enviar mensajes y se muestren todos los emitidos por el resto de
usuarios y una barra de herramientas que permita iniciar una videoconferencia, un
chat privado, cambiar el tipo de letra a mostrar, cerrar la ventana de chat, guardar
la conversación en curso en un fichero y limpiar los mensajes mostrados.

Éste chat estará formado por tres componentes gráficos: Una lista de usuarios
conectados, un chat y una barra de herramientas. De éstos, el único que deberá
implementarse específicamente será la barra de herramientas, el resto serán
provistos por el framework. El sistema de videoconferencia será el mismo que se
explicó dentro de la sección dedicada al subsistema de videoconferencia.

Éste plugin aparecerá en el listado de aplicaciones de la aplicación cliente con el


nombre “Chat” y estará contenido en el fichero “chat.jar” de la carpeta “plugin”
(subcarpeta de la carpeta donde se encuentre situado el ejecutable
correspondiente a la aplicación cliente final). La descripción que deberá tener el
plugin será la siguiente: Chat con videoconferencia integrada. Permite mensajes
privados y públicos. Tendrá el sistema de control de versiones habilitado y su
versión será la número 1.

El diseño de la interfaz gráfica que deberá tener éste plugin se muestra a


continuación:

Ilustración 68: Plugin Chat

Proyecto Fin de Carrera | 149


• El gestor de plugins permitirá agregar o eliminar plugins a la aplicación cliente sin
necesidad de copiar y pegar los ficheros .jar en la carpeta correspondiente.
También permitirán ver los siguientes datos de un plugin: Nombre, Versión, Fichero
jar que lo contiene y si es visible o no en la lista de aplicaciones. Cualquiera de los
plugins podremos mostrarlo u ocultarlo de forma dinámica. Ésto se podrá realizar
gracias al contenedor de plugins que se explicó con anterioridad.

El gestor de plugins tendrá como nombre “Gestor”, como versión la 1, no tendrá


control de versiones (Se considera algo ya terminado), estará contenido en el
fichero “gestor.jar” y su descripción deberá ser: Gestor de los plugins instalados en
esta aplicación.

El diseño de la interfaz que deberá tener éste plugin se muestra a continuación:

Ilustración 69: Plugin gestor de plugins

• La pizarra permitirá realizar dibujos de forma colaborativa. Todos los usuarios


conectados al sistema podrán realizar apuntes en ésta pizarra o borrar elementos

Proyecto Fin de Carrera | 150


de ella. El contenido de ésta pizarra será exactamente el mismo para todos los
usuarios, incluida la pila que permite deshacer o rehacer acciones. Ésta pizarra
estará basada en el lienzo compartido que se explica detalladamente en la sección
dedicada a componentes gráficos reutilizables y en la sección dedicada a la edición
compartida de documentos, con lo que cualquier detalle de su implementación
sería redundante.

La pizarra tendrá como nombre “Pizarra”, tendrá el control de versiones activado y


su versión será la 5 (hubo 4 prototipos anteriores descartados en fases
preliminares de desarrollo). Estará contenido en el fichero “pizarra.jar” y su
descripción deberá ser: Pizarra para pintar junto a tus colaboradores.

El diseño de la interfaz que deberá tener éste plugin se muestra a continuación


(como se podrá observar, es muy parecido al del editor compartido):

Visualización de los plugins disponibles para un cliente (PluginList)

Como anteriormente se ha descrito,


los plugins son cargados de forma
dinámica a partir de una serie de
ficheros .jar. Cada plugin tendrá
dos elementos visibles para el
usuario final: Un nombre y una
descripción. Se creará una lista
rellena mediante con la colección
de objetos DabstractPlugin del
sistema. La visualización en la lista
se hará de forma correcta gracias a
que el método “toString” de la clase
DabstractPlugin estará Ilustración 70: Plugin Pizarra Compartida
sobrecargado para mostrar el nombre del plugin.

Proyecto Fin de Carrera | 151


La lista con los nombres de los plugins disponibles la irá actualizando convenientemente
la aplicación cliente, ya que con el paso del tiempo existe una alta probabilidad de que
cambie (Se agreguen plugins, se actualicen, se eliminen, etc.).

Puesto que se mostrará un tooltip al pasar el raton sobre cada elemento de la lista, será
necesaria la implementación de un componente gráfico específico para ello. Este
componente se llamará “PluginList”. Simplemente será una especialización de la clase
JList de Java, donde se agregará un método para controlar que al pasar el raton sobre
una entrada de la lista se muestre el tooltip correspondiente. El contenido del tooltip de
cada plugin se corresponderá con su descripción, por lo que nuevamente se hace
hincapié en el hecho de que se introduzca una descripción en los plugins desarrollados.

Como mejora a éste sistema, en un futuro se plantea el hecho de que se intercambie ésta
lista por un árbol, donde cada rama se corresponda a un categoría de entre las posibles y
cada hijo sea un plugin de esa categoría.

La interfaz gráfica que deberá tener éste componente se muestra a continuación.

Ilustración 71: Lista de aplicaciones

Proyecto Fin de Carrera | 152


Diagrama del clases

Para terminar de detallar el subsistema dedicado a los plugins, se muestra el siguiente


diagrama de clases.

Ilustración 72: Diagrama de claes del subsistema Plugin

Tal y como se explicó anteriormente, la parte dedicada al cálculo paralelo no ha sido


integrada en éste diagrama por cuestiones de espacio. Su diagrama de clases puede
consultarse en la sección dedicada a la explicación exhaustiva del funcionamiento de los
plugins de cálculo paralelo.

Proyecto Fin de Carrera | 153


7.2.4. Subsistema de videoconferencia

Uno de los pilares fundamentales de la comunicación en sistemas colaborativos es la


videoconferencia. Se deberá aportar un subsistema capaz de realizar una comunicación
entre varios usuarios tanto de forma visual como auditiva. La implementación de un
sistema de videoconferencia es de una alta complejidad debido al amplio territorio de
subproblemas que se deben solventar: Acceso a hardware de forma eficiente, transmisión
de datos en tiempo real a través de la red, control de flujo en la red (evitar saturación de
bufferes), reproducción de imagen y sonido, etc. Dividiremos por tanto el problema en dos
partes claramente diferenciadas: Captura, transmisión y reproducción de vídeo y captura,
transmisión y reproducción de audio. Cada uno de los aspectos anteriores requerirá de un
gran esfuerzo de implementación, con lo que deberán ser detallados ampliamente en las
siguientes secciones.

Captura de vídeo

Para realizar la captura de vídeo haremos uso de unas bibliotecas de código abierto
conocidas como LTI-Civil (disponibles en http://lti-civil.org). La primera restricción que nos
impondrá el uso de éstas bibliotecas es que el acceso al hardware en los principales SO's
no se puede realizar desde Java con la misma eficiencia, con lo que obtendremos los
siguientes ratios de captura:

! 20 imágenes por segundo a 320x240 pixels en Windows


! 7 imágenes por segundo a 160x120 pixels en Linux
! 7 imágenes por segundo a 640x480 pixels en Mac OS X

Debido a ésto, deberemos de hacer lo más eficientemente posible tanto la transmisión


como la reproducción de éstas capturas, ya que de por sí, veremos los vídeos a “saltos”
(para visualizar un vídeo con suavidad, éste debería de reproducirse a 25 imágenes por
segundo aproximadamente).

Proyecto Fin de Carrera | 154


El modo de capturar es muy sencillo, y se dispone de una amplia documentación y
diversos ejemplos en la propia página web de las bibliotecas. Básicamente se deberá de
abrir un flujo de datos con el dispositivo de captura, prácticamente igual que si fuese un
fichero. Se deberá también implementar un capturador de eventos para éste flujo, de tal
forma que cada vez que se capture una imagen se envíe por la red hasta el otro cliente
con el que estamos realizando la videoconferencia. El lanzamiento de eventos desde el
flujo también lo realiza la biblioteca. La captura del evento en sí se implementará en la
clase Videoconferencia, junto con el sistema de transmisión de vídeo, que se comenta a
continuación.

Transmisión de vídeo

La transmisión de vídeo debe ser lo más óptima posible en todos los casos para evitar
que éste proceso tenga un impacto significativo con respecto a las imágenes por segundo
que se reproducirán, que de por sí, debido a las limitaciones de acceso a hardware son
muy pocas.

A la hora de realizar la transmisión de vídeo debemos tener en cuenta lo siguiente:

• No importa demasiado que una imagen llegue corrupta o no, puesto que se
actualizará en un plazo muy pequeño de tiempo. Ésto implica que no sea necesario
realizar un control exhaustivo de errores en la transmisión.
• Las imágenes se pueden transmitir una a una, ya que la velocidad de captura es
muy pequeña en comparación con la velocidad de transmisión, con lo que no
merece la pena la implementación de bufferes intermedios. Si se consiguiera en un
futuro una mejora sustanciosa en la velocidad de captura del hardware, entonces
ésto podría ser interesante para poder ver vídeo con mayor fluidez.
• La transmisión no puede realizarse haciendo uso de JavaSpaces. Será necesario
idear un sistema de sockets para transmitir las imágenes entre dos clientes. Ésto
se integrará en la clase donde se realiza la captura desde el hardware. El uso de
RMI podría facilitar el desarrollo, pero tendría un impacto muy importante en la

Proyecto Fin de Carrera | 155


eficiencia.
• La calidad de las imágenes no es demasiado importante, con lo que se podrán
someter a procesos de reescalado y compresión sin ningún problema.
• Para evitar que la transmisión de imágenes sobrecargue la red, las imágenes se
someterán a un preprocesamiento que intentará minimizar en lo posible los bits que
requerirá cada una. Para ello, se convertirán a jpeg antes de ser transmitidas. El
impacto que tiene ésta conversión, puesto que las imágenes capturadas tendrán
poca cantidad de pixels, es despreciable.

En base a los puntos anteriores, extraemos que el sistema de transmisión de vídeo


funcionará de la siguiente manera:

• Un cliente indica el hecho de iniciar una videoconferencia.


• El sistema comprueba los dispositivos de captura disponibles y selecciona uno de
ellos de forma automática. Entre los formatos de vídeo que soporte el dispositivo,
se selecciona aquel que proporcione mayor cantidad de imágenes por segundo.
• Se crea un socket servidor en un puerto determinado del cliente (en particular,
usaremos el 4445, por no estar entre los usados habitualmente por otras
aplicaciones).
• Se comienza la captura de imágenes desde el dispositivo.
• Una vez que el otro cliente acepte la videoconferencia, se abre la conexión
mediante sockets entre ambos.
• Cada vez que se captura una imagen, se intenta enviar hacia el otro cliente con el
que estamos realizando la videoconferencia. Ocurrirá una excepción controlada en
el caso de que el otro cliente no haya aceptado aún el establecimiento de la
videoconferencia.
• El otro cliente realizará el mismo proceso aquí descrito desde su aplicación cliente.

Obviamente, aunque es importante destacarlo, si iniciamos dos aplicaciones cliente en el


mismo computador, ocurrirán conflictos que impedirán el correcto funcionamiento de la
transferencia de imágenes.

Proyecto Fin de Carrera | 156


El siguiente diagrama ilustra el funcionamiento de la captura y transmisión de vídeo.

Ilustración 73: Esquema de funcionamiento de la


transmisión de vídeo

Cada una de las imágenes transmitidas requerirá ser reproducida en el otro extremo. Éste
proceso se describirá en la siguiente sección.

Reproducción de vídeo
La reproducción de vídeo es un proceso bastante simple según el esquema de captura y
transmisión usado. Puesto que se realiza una transmisión imagen a imagen, tan solo
tendremos que crear un panel donde se muestren éstas imágenes una a una. Para
realizar ésto, se implementará la clase ImageComponent, que será la encargada de
mostrar cada imagen, y que será una subclase de JPanel. Para mostrar una imagen se
deberá sobrecargar el método paint, poniéndole el modificador synchronized, puesto que
se deben evitar conflictos a la hora de pintar las imágenes (se puede dar el caso de que
no se haya terminado de pintar una imagen y que llegue otra y se vuelva a llamar al
método paint).

En la ventana final donde se mostrará éste componente, se mostrará también una versión

Proyecto Fin de Carrera | 157


más pequeña que permita visualizar lo que el otro cliente está viendo, es decir, un
pequeño panel donde se vea lo que nuestro propio dispositivo de captura esté
capturando. El diseño de ésto último se muestra a continuación:

Ilustración 74: Esquema del panel de videoconferencia

Se deberán, así mismo, implementar dos hebras encargadas de leer la imagen local y la
remota cada cierto tiempo para actualizar ambos paneles. La lectura deberá realizarse
cada 30 milisegundos aproximadamente (33 asignaciones por segundo) para mostrar la
imagen remota y cada 100 milisegundos (10 asignaciones por segundo) para mostrar la
imagen local (La fluidez de la imagen local no tiene importancia si lo comparamos con el
rendimiento general del subsistema).

Captura de audio
La captura de audio se realizará mediante diversas clases que posee la SDK de Java.
Será necesario implementar una clase que se encargue de abstraer ésta captura, puesto
que las clases provistas por Sun son complejas de usar y difíciles de comprender en gran
medida.

Proyecto Fin de Carrera | 158


Se implementarán dos clases para realizar la abstracción anteriormente descrita: Una
clase abstracta con los parámetros de bajo nivel usados (tamaño del buffer, código de
formato de audio, mezclador, línea de datos, etc.) y otra clase que implemente ésta clase
abstracta y que se encargue de la creación de los flujos sobre las líneas de datos
asociadas al audio, de la captura del audio, etc. Éstas clases serán conocidas
respectivamente como AudioBase y CapturaAudio.

Éstas clases harán uso de flujos de entrada de audio, flujos de salida de datos (bytes)
para posteriormente reproducir o transmitir el audio capturado, de un mezclador y de una
linea de datos. El mezclador será el dispositivo desde el cual se capturará el audio. La
linea de datos será la línea específica dentro del mezclador desde la que capturaremos.
Según el código de formato que se utilice, se capturará de una línea u otra.

El flujo de entrada de audio será provisto por la clase AudioInputStream de Java. El flujo
de salida será un OutputStream, también de Java, que nos permitirá obtener los bytes
contenidos en él.

Como se puede observar por lo anterior, se requerirán bastantes datos de configuración


para realizar una captura adecuada del audio. Éstos datos serán almacenados en clases
específicas de la capa de modelo del subsistema. Las clases que almacenarán los datos
de configuración serán las siguientes:

• ConfiguracionAudio. Ésta clase mantendrá todos la información proporcionada


por el SO del cliente acerca de dispositivos de audio: Formatos existentes, volumen
de cada puerto, puertos, mezcladores, etc. También se almacenará el tamaño del
buffer en en bytes y en milisegundos.
• ConstantesAudio. Tendrá una serie de constantes para facilitar el uso de la clase
ConfiguracionAudio.

Será absolutamente necesario que se realice un sistema gráfico de configuración de


audio. Éste sistema gráfico permitirá configurar los parámetros de las clases anteriores,
de tal forma que el cliente obtenga el resultado esperado. Éste panel de configuración

Proyecto Fin de Carrera | 159


habrá que integrarlo con la ventana final del subsistema de videoconferencia. A
continuación se muestra una captura del panel de configuración de audio que se usará.

Ilustración 75: Panel de configuración de audio

Como se puede observar, se permitirá elegir mezcladores para el micrófono y el altavoz,


poner en silencio alguna de las líneas, elegir el tamaño del buffer en milisegundos
(podemos ajustar ésto para mejorar el rendimiento en conexiones lentas) e iniciar un test
del micrófono para comprobar que la configuración es adecuada.

Haciendo uso de las clases descritas previamente, con los datos proporcionados
mediante el panel anterior, se establecerá una conexión mediante la cuál se transmitirá un
buffer capturado desde un cliente hasta otro, para que éste último lo reproduzca.

Transmisión de audio
La transmisión del audio es una parte sumamente compleja, puesto que requerirá un
cierto control de errores y se deberá controlar el flujo de datos para evitar saturaciones en
el buffer de entrada.

Para realizar ésta transmisión de la forma más adecuada se establecerá una red de
comunicación base, que será una implementación mediante sockets del protocolo TCP.
De éste protocolo aprovecharemos principalmente el control de flujo que proporciona y el
hecho de que sea orientado a conexión. Éste control de flujo se realiza mediante buffers
de envío y de recepción. Del resto de tareas se encargarán los sockets. Se deberán crear
métodos para poner una red en escucha y para abrir y cerrar la conexión y para crear los

Proyecto Fin de Carrera | 160


buffers de envío y recepción.

Haciendo uso de ésta red de comunicación se establecerá un protocolo Handshake que


funcionará en dos partes claramente diferenciadas: Una parte activa (encargada de iniciar
la “conversación”) y otra parte pasiva (encarga de escuchar y procesar). El
funcionamiento de ambas partes se explica a continuación:

Handshake activo
Fase I
• Se envía un entero con un valor especial (PROTOCOL_MAGIC). Éste valor es
0x43484154.
• Se envía un entero con la versión del protocolo (PROTOCOL_VERSION). En
nuestro caso es la versión 1.
• Se envía el código de formato para el audio en forma de entero.

Fase II
• Se lee el buffer que se envió desde el otro extremo.
• Si el buffer contiene PROTOCOL_ACK (el valor entero 1001) entonces se
establece la conexión.

Handshake pasivo

Fase I
• Se leen tres enteros (12 bytes).
• Se comprueba que el primer entero sea PROTOCOL_MAGIC, el segundo
PROTOCOL_VERSION y el tercero un código de formato válido.
• Si todo fue correcto, se escribe PROTOCOL_ACK. Si no, se escribe
PROTOCOL_ERROR (el valor entero 1002).

El siguiente diagrama describe gráficamente el proceso anteriormente descrito:

Proyecto Fin de Carrera | 161


Ilustración 76: Protocolo Handshake para la transmisión de
audio

Puesto que la conexión podrá admitir ciertos parámetros de configuración (como los
puertos usados o el código de formato para la transmisión) será necesario agregar un
sistema de configuración también para la transmisión. Éste sistema de configuración se
integrará con el descrito para la captura en una ventana con dos pestañas. La ventana
final que deberá implementarse, mostrándose la pestaña correspondiente a la
configuración de la conexión se muestra a continuación.

Ilustración 77: Panel de configuración de la conexión


para la transmision del audio

Proyecto Fin de Carrera | 162


Reproducción de audio
Para la reproducción del audio se hará uso de la clase aportada por Java conocida como
SourceDataLine. Simplemente se deberá escribir en ésta linea de datos el buffer recibido
desde el otro extremos de la red. La linea de datos donde se escriba habrá sido
seleccionada mediante el panel de configuración descrito en la sección dedicada a la
captura de audio.

La dificultad de la reproducción está en sincronizar correctamente las hebra de


reproducción, puesto que hará uso de métodos que harán uso de forma común del buffer.
También deberemos esperar a que el buffer tenga algún contenido antes de leerlo, puesto
que si leemos un buffer vacío introduciremos silencios en la reproducción. Tampoco
podremos permitir que varias hebras inicien la reproducción de un mismo buffer, puesto
que se escucharía la voz en “coro” (varias voces que hablan a la vez, dicen lo mismo,
pero existe un desplazamiento temporal en el inicio de cada voz).

Integración de vídeo y audio


Para realizar una integración adecuada del audio y del vídeo se creará una ventana con
un botón que permita iniciar la captura del audio y del vídeo y otro de configuración del
audio. Ésta ventana tendrá integrada el panel descrito en la sección dedicada a la
reproducción del vídeo. Ésta ventana deberá tener un aspecto como el que sigue:

Ilustración 78: Ventana de


videoconferencia

Proyecto Fin de Carrera | 163


Puesto que se requerirán IP's para las conexiones entre sockets, éstas IP's se
transmitirán mediante un evento especial, el cuál, al ser procesado en cada extremo,
permitirá que se abra automáticamente la ventana anteriormente descrita en el cliente
donde ha llegado la solicitud de nueva videoconferencia. El funcionamiento de éste
evento será como sigue.

! Un cliente envía un evento de inicio de videoconferencia a un destinatario. En éste


evento tendrá, además de datos de metainformación, su dirección IP. La ventana
de videoconferencia se abre automáticamente.
! El cliente de destino recibe el evento, lo procesa, abre la ventana de
videoconferencia y reenvía un evento confirmando la aceptación del proceso. En
éste evento de confirmación se agrega la dirección IP de éste cliente.

Éste evento se implementará en la clase DJChatEvent.

Diagrama de clases

A continuación se muestra el diagrama de clases del subsistema de videoconferencia


completo. Como se puede observar por el propio diagrama, la implementación de la parte
orientada al audio implicará un esfuerzo muy superior a la parte de vídeo, debido a los
especiales requisitos de la primera.

Proyecto Fin de Carrera | 164


Ilustración 79: Diagrama de clases para el sistema videoconferencia

Proyecto Fin de Carrera | 165


7.2.5. Aplicación cliente

La aplicación cliente será un caso específico de aplicación distribuida que puede ser
creada mediante la infraestructura descrita a lo largo de éste documento. El esquema de
cualquier aplicación distribuida que se desee implementar (incluyendo, por supuesto, a la
aplicación cliente) se muestra a continuación.

Ilustración 80: Esquema básico de una aplicación


creada haciendo uso de nuestro Framework
Ésta aplicación cliente, además, hará uso del resto de subsistemas descritos durante la
etapa de diseño del sistema.

Para la gestión de eventos de los componentes de los que hace uso, se encargará de
instanciar un objeto de la clase DConector. También se encargará de leer los plugins
disponibles y de realizar las distintas comprobaciones de seguridad necesarias (permisos
sobre documentos, componentes, de los usuarios, etc.). En la mayoría de los casos, se
encargará de mostrar mensajes que informen al usuario final de las posibles
eventualidades ocurridas.

Fundamentalmente, a nivel, gráfico, tendrá tres componentes: Un listado con las


aplicaciones, un listado de usuarios conectados y roles posibles y un árbol de

Proyecto Fin de Carrera | 166


documentos. El diseño del interfaz gráfico está ampliamente explicado en la sección
dedicada a ello.

Gestión del listado de aplicaciones


Para la gestión del listado de aplicaciones se hace uso del subsistema de plugins. Éste
subsistema provee de una clase de la capa de GUI llamada PluginList y de otra de la capa
de modelo, que actúa como única interfaz entre la capa GUI y la capa física del
subsistema, llamada PluginContainer.

Mediante PluginList, mostraremos al usuario final las aplicaciones (plugins) de los que
dispone. Para actualizar ésta lista ante diversas eventualidades (agregar, eliminar,
actualizar u ocultar plugins) se hace uso de PluginContainer. Ésta última también se
encargará de recuperar los plugins de la carpeta “plugin”. Cada vez que se actualice un
elemento en la capa de modelo, actualizaremos la lista convenientemente.

Gestión de usuarios
Para la gestión de usuarios se hará uso del subsistema de videoconferencia, de gestión
de metainformación del sistema, de gestión de metainformación de ficheros y de sistema
de ficheros. Gráficamente se mostrará un pequeño árbol donde se podrán observar los
usuarios conectados y el rol de cada uno. Bajo éste árbol tendremos una pequeña barra
de herramientas que permitirá realizar diversas tareas de sistema o comunicarnos con
otros usuarios. Éstas operaciones se describen a continuación:

• Editar la metainformación del sistema. Permitirá mostrar la metainformación del


sistema y editarla. Se requerirá ser un usuario con permisos de administración. En
caso de no serlo, la aplicación cliente se encargará de deshabilitar éste botón.

• Cambiar el rol actual. Permitirá cambiar el rol actual del usuario. El cambio de rol
se reflejará en la interfaz de usuario habilitando o deshabilitando
correspondientemente ciertos componentes o mostrando u ocultando documentos.

Proyecto Fin de Carrera | 167


• Enviar una petición de chat a un usuario. Permitirá, previa selección en el árbol
de usuarios de un usuario concreto que no sea el propio usuario local, enviar una
petición de chat. Ésta petición se reflejará en el usuario remoto con la apertura de
la ventana de chat. Hasta que el usuario remoto no responda, el usuario local no
podrá iniciar la escritura de mensajes.

• Mensajería asíncrona. Permitirá enviar un mensaje asíncrono a un usuario, esté o


no conectado al sistema. Éste sistema pretende aportar una funcionalidad similar al
e-mail convencional. Se abrirá una ventana que permitirá seleccionar un usuario,
introducir un asunto e introducir un mensaje. Tras pulsar en el botón enviar, se
creará un documento en la carpeta Incoming con permiso de lectura y escritura
solo para el destinatario. También poseerá la propiedad del documento y su rol por
defecto será el rol propietario del mensaje. Éstos mensajes se pueden abrir como
cualquier otro documento. Se abrirán con el editor compartido, al igual que el resto
de documentos. Si en algún momento queremos compartir un mensaje, también
podremos hacerlos, asignándole previamente los permisos oportunos. El diseño de
la ventana de envío de mensajes se muestra a continuación:

Ilustración 81: Ventana de composición de mensajes asíncronos

Proyecto Fin de Carrera | 168


• Enviar una petición de videoconferencia a un usuario. Permitirá, previa
selección en el árbol de usuarios de un usuario concreto que no sea el propio
usuario local, enviar una petición de videoconferencia. Ésta petición se reflejará en
el usuario remoto con la apertura de la ventana de videoconferencia. La ventana
que aparecerá será la implementada en el subsistema de videoconferencia.

Gestión de documentos
La gestión de documentos requerirá del uso del subsistema de metainformación de
ficheros y del sistema de ficheros. Se mostrará un componente gráfico que permite
mostrar en árbol los documentos. Éste componente gráfico asignará distintos iconos a los
distintos tipos de documentos soportados y de forma gráfica se mostrará que alguien está
editando un documento (mediante un icono especial). A éste componente gráfico se le
agregará una barra de tareas que permitirá acceder a las siguientes operaciones que
provee la clase que modela el árbol de documentos:

• Abrir un documento. Tras seleccionar un documento del árbol de documentos y


pulsar éste botón, se mostrará el editor compartido de documentos que se ha
descrito en secciones anteriores. En caso de no poder interpretar mediante ningún
filtro el documento en cuestión, la aplicación permitirá abrir mediante el filtro de
texto. En éste último caso, se nos mostrará en el editor compartido una
representación en texto del contenido del documento. Podremos realizar también
ésta operación al hacer doble click sobre cualquier documento. Ambas opciones
son equivalentes. Cuando abramos un documento, mientras éste proceso se éste
ejecutando se podrá ver una barra de carga en la parte inferior de la aplicación
cliente.

• Reenviar un mensaje asíncrono a un destinatario. En la carpeta Incoming


dispondremos de los mensajes asíncronos que nos hayan enviado el resto de
usuarios. Si alguno de éstos mensajes queremos reenviarlo a otro usuario, nos
bastará con pulsar en éste botón, habiendo seleccionado previamente el mensaje.
Éste botón abrirá la ventana de envío de mensajería asíncrona para que
seleccionemos el destinatario.

Proyecto Fin de Carrera | 169


• Imprimir un documento. Si seleccionamos un documento podremos enviarlo a
imprimir sin necesidad de abrirlo con el editor compartido. Si el documento no se
puede interpretar mediante ningún filtro, entonces se preguntará si se desea enviar
a imprimir como si fuese un texto.

• Agregar un documento al sistema. Permite abrir un selector de ficheros locales


al usuario para que se seleccione uno y se envíe al sistema. A partir de ese
momento, el fichero podrá ser compartido por el resto de usuarios. Por defecto se
introducirá en la carpeta raíz, pero si tenemos seleccionada otra carpeta, entonces
se nos cargará en ésta.

• Descargar una copia local de un documento del sistema. Permitirá descargar


cualquier documento de forma local al usuario. No se requieren comprobaciones de
seguridad, puesto que si no tenemos permiso de lectura sobre un documento, éste
no se nos muestra. Antes de descargar un fichero, deberemos seleccionarlo en el
árbol

• Eliminar un documento del sistema. Permite eliminar un documento


seleccionado del sistema. Para eliminar un directorio, deberemos eliminar su
contenido previamente. Para eliminar tanto un directorio como un documento
deberemos tener permisos de escritura sobre él. Si ésto no ocurre, la aplicación
muestra un mensaje informando de éste hecho.

• Agregar una carpeta al sistema. Permite agregar una carpeta al sistema. Si no


hemos seleccionado ninguna carpeta, se asumirá que se desea agregar a la raíz.
Deberemos tener permiso de escritura en la carpeta donde crearemos la nueva
subcarpeta, de lo contrario se mostrará un mensaje informándonos de ello.

Proyecto Fin de Carrera | 170


Ilustración 82: Ventana de gestión de
la metainformación de los
documentos
• Mostrar las propiedades de un documento del sistema. Al pulsar sobre éste
botón se mostrará una ventana donde se podrán visualizar las siguientes
propiedades: El nombre del documento, el usuario propietario, el rol que tenía
cuando creó el documento, si el documento es un directorio o no, los usuarios que
se encuentran editándolo en éstos momentos y los permisos para el usuario
propietario, el rol propietario y otros usuarios. En ésta ventana podremos modificar
el nombre del documento y sus permisos (si tenemos a su vez permisos
suficientes). El diseño gráfico de ésta ventana se muestra a continuación:

Interfaz gráfica final


La interfaz gráfica final de la aplicación cliente quedó expuesta en la sección dedicada al
diseño de ésta. No obstante, se mostrará en una imagen el uso que hace cada elemento
de la interfaz gráfica de cada uno de los subsistemas implementados. Nótese que éstos
subsistemas harán uso de otros subsistemas, con lo que finalmente, todos ellos se usarán
de un modo u otro.

Proyecto Fin de Carrera | 171


Ilustración 83: Ventana Principal de la aplicación y susbistemas involucrados

Proyecto Fin de Carrera | 172


8. Componentes gráficos reutilizables (Beans)

Todo componente gráfico que desee ser replicado deberá implementar la interfaz que se
describe a continuación. Ésta interfaz se llamará Dcomponente.

" public void activar() Activará el componente.


" crearHebraProcesadora() Devolverá la hebra procesadora que gobernará el
procesamiento de los eventos de entrada.
" public void desactivar() Desactivará el componente.
" public Integer getID() Obtendrá el ID del componente. No existirán dos componentes
dentro de la misma aplicación que tengan el mismo ID.
" public int getNivelPermisos() Obtendrá el nivel de acceso actual al componente.
" public String getNombre() Obtendrá el nombre del componente. Al igual que el ID, éste
será único con respecto al resto de componentes de la aplicación.
" public void iniciarHebraProcesadora() Iniciará la hebra encargada de procesar los
eventos que le llegarán al componente.
" obtenerColaRecepcion() Devolverá la cola de envío del componente.
" obtenerColaRecepcion() Devolverá la cola de recepción del componente.
" obtenerComponente(int num) Devolverá el componente hijo que tiene el número
indicado.
" obtenerComponente(String nombre) Devolverá el componente hijo que tiene como
nombre el indicado.
" obtenerNumComponentesHijos() Devolverá el número de componentes hijos que tiene el
componente.
" obtenerPadre() Devolverá el componente padre el componente.
" padreOcultado() Notificación de que algún componente en el camino desde el
componente que recibe la notificación hasta el nivel superior de la jerarquía ha sido
ocultado.

Proyecto Fin de Carrera | 173


" public void procesarEvento(DEvent evento) Se encolará un nuevo evento en la cola de
recepción del componente que posteriormente será procesado por la hebra
procesadora de eventos.
" public void setNivelPermisos(int nivel) Cambiará el nivel de acceso al componente. Se
deberá especificar un permiso mayor o igual que 10 y menor que 20 para el
permiso de lectura y mayor o igual que 20 para permiso de lectura/escritura.
" public void sincronizar() Lanzará el evento correspondiente para indicar que se desea
sincronizar el componente con el estado actual. Podrá haber algún componente
que no necesite de sincronización.

8.1. DcomponenteBase

Descripción

Implementar un componente replicado usando directamente la interfaz DComponente


puede ser algo tedioso. Parte del comportamiento de los componentes replicados será
común a todos. Tal y como se especificó en uno de los requisitos de construcción de la
API se buscaría la mayor simplicidad para el programador por lo que se ha agrupado todo
ese comportamiento común en una clase denominada DComponenteBase que
implementa la interfaz DComponente. Por tanto para crear un nuevo componente solo
deberemos heredar de esta clase y añadir el comportamiento no común del componente.
En el ejemplo de creación de componentes se explicará con detalle como realizar este
proceso.

El DComponenteBase consta de 2 paneles, uno que alberga los componentes que


conforman el componente que se construye y otro que se situará por delante de ese en
caso de que el usuario no tenga permiso para ver dicho componente. Gracias e esta
estructura se facilita bastante la creación de componentes mediante el uso de
herramientas de desarrollo tales como Netbeans o Eclipse.

La funcionalidad que ya tiene implementada el DComponenteBase es la siguiente:

" Interfaz de envío de eventos: Disponemos del método enviarEvento() que nos

Proyecto Fin de Carrera | 174


proporciona una manera sencilla de mandar eventos al exterior. Nos
despreocuparemos de la tarea de saber si estamos en comunicación directa con el
DConector o por el contrario somos hijos de otro componente. Además se
establecen de forma automática una serie de campos que necesariamente deben
tener un valor cuando un componente genera un evento. Estos campos son:

" componente: Identificado numérico del componente


" nombreComponente: Cadena de texto identificativa del componente.
" origen: Origen del evento
" destino: Destino del evento
" ultimoProcesado: Número de secuencia del último evento que ha sido
procesado por el componente. Normalmente se usa con fines de
sincronización.

" Colocación automática de los eventos entrantes en la cola de recepción.

" Procesamiento automático de cierta metainformación. Los mensajes procesados


de forma automática son los siguientes:

" Establecimiento del permiso correcto al inicio de la aplicación una vez


devuelta por el servidor de metainformación.
" Establecimiento del permiso correcto cuando se cambia de rol. Debemos
tener en cuenta que un cambio de rol puede significar un cambio en los
permisos del componente.
" Establecimiento del permiso correcto cuando se cambia el permiso del
componente en el servidor de metainformación, tanto cuando sea a nivel de
usuario como cuando sea a nivel de rol.

" Envío de los eventos de metainformación hacia abajo en la jerarquía. Como ya se


ha comentado los componentes conforman una estructura jerárquica. Los
componentes que reciben las notificaciones del servidor de metainformación son

Proyecto Fin de Carrera | 175


aquellos que están en comunicación directa con el DConector. Por tanto si
queremos que lleguen a todos los componentes de la aplicación los componentes
del nivel superior deben comunicarlo a sus hijos y así sucesivamente hasta llegar a
los componentes que están en el nivel más bajo de la jerarquía.

" Inicio automático de la hebra procesadora del componente así como la de sus
hijos. De esta forma nos despreocupamos de iniciar la hebra nosotros y que sea en
el momento correcto.

Diagrama UML

Ilustración 84: Diagrama de clases para DComponenteBase

Proyecto Fin de Carrera | 176


Comentario sobre los métodos

" activar(): Este método se encarga de activar el componente. Por si solo no tiene
funcionalidad alguna aunque normalmente no será necesario sobreescribirlo.
" Métodos add(…): Estos métodos nos permiten añadir elementos directamente al
panel de contenido.
" conectadoDC(): Devuelve TRUE en caso de que el componente tenga conexión
directa con el DConector. FALSE en cualquier otro caso. No es necesario que se
sobrescriba.
" crearHebraProcesadora(): Uno de los métodos mas importantes para el desarrollo de
nuevos componentes a partir de este. Este método devuelve una hebra que será la
encargada del procesamiento de los eventos que lleguen al componente. La clase
que debe devolverse es una subclase de HebraProcesadoraBase.
" desactivar(): Desactiva el componente. Normalmente no es necesario sobreescribirlo.
" enviarEvento(): Mediante este método realizamos el envío de un evento. No es
necesario sobrescribirlo ya que implementa la funcionalidad deseada.
" getID(): Devuelve el ID del componente. No es necesario sobreescribirlo.
" getNivelPermisos(): Devuelve el nivel de permisos del componente. No es necesario
sobrescribirlo.
" getNombre(): Obtiene el nombre del componente. No es necesario sobreescribirlo.
" iniciarHebraProcesadora(): Inicia la hebra procesadora. No es necesario
sobreescribirlo.
" mostrar(): Muestra el componente y notifica a los hijos que ha sido mostrado. No se
debe sobrescribir.
" obtenerColaEnvio(): Nos devuelve la cola que está usando como cola de envío. No es
necesario su uso para la generación de nuevos componentes.
" obtenerColaRecepcion(): Nos devuelve la cola que está usando como cola de
recepción. No es necesario su uso para la generación de nuevos componentes.
" obtenerComponente(int num): Otro método bastante importante. Deberemos
sobrescribirlo cuando diseñemos un nuevo componente para que devuelva el
componente hijo con el número indicado. Los componentes hijos irán numerados
comenzando por el 0.

Proyecto Fin de Carrera | 177


" obtenerComponente(String nombre): Este método es algo menos importante que el
anterior. Debe ser sobrescrito para que devuelva el componente con el nombre
indicado. No es necesario obligatoriamente sobreescribirlo.
" obtenerNumComponentesHijos(): Método muy importante. Debe ser sobrescrito al
diseñar nuevos componentes para que devuelva el número de hijos que tiene el
componente.
" obtenerPadre(): Devuelve el componente padre. No es necesario sobreescribirlo.
" obtenerPanelContenido(): Devuelve la instancia del panel que se está usando como
panel de contenido. Es útil por si deseamos hacer algún tipo de cambio en él.
" ocultar(): Oculta el componente. No debe ser sobrescrito.
" oculto(): Devuelve si el componente está oculto (TRUE) o no (FALSE).
" padreMostrado(): Mediante este método se notifica a los componentes hijos que el
componente ha sido mostrado. No debe sobrescribirse.
" padreOcultado(): Igual que el anterior pero para el caso que el componente se oculta.
" procesarEvento(): Añade un evento a la cola de recepción. No necesita ser
sobrescrito para crear nuevos componentes.
" procesarEventoHijo(): Este método también es importante sobreescribirlo cuando
creamos nuevos componentes que van a estar compuestos de otros componentes
replicados. Cuando un componente que no está directamente en contacto con el
DConector los eventos que genera se le notifican al componente padre. El modo de
notificárselos es mediante la llamada de este método del componente padre.
" procesarMetaInformacion(): Mediante este método se procesa un evento de
metainformación. No es necesario sobrescribirse salvo que se necesite procesar
una metainformación diferente de la soportada por defecto. Si se sobrescribiera
este método, su implementación en la clase hija deberá llamar de todas formas a
éste método en la superclase.
" setLayout(): Especifica un layout para el panel de contenido. No es necesario
sobrescribirse.
" setNivelPermisos(): Establece el nivel de permisos del componente. No es necesario
sobrescribirse. En caso de que sí se haga sucede como en el método de
procesamiento de metainformación, deberá se llamado éste método en la
superclase.

Proyecto Fin de Carrera | 178


" sincronizar(): Este método disparará el evento de petición de sincronización en
aquellos componentes que necesiten sincronizar su estado al iniciarse. En el
ejemplo de creación de componentes se entenderá su utilidad.

Proyecto Fin de Carrera | 179


8.2. Hebras procesadoras

Cada componente replicado deberá tener una hebra que se encargue de procesar los
eventos que reciba. Conceptualmente a esta hebra se la ha denominado hebra
procesadora y en los ejemplos de desarrollo de componentes se pueden encontrar
ejemplos de cómo implementarlas.

Un componente deberá estar preparado para cuando se le “pregunte” cual va a ser la


hebra que se va a encargar de procesar los eventos entrantes. Para ello deberá tener
implementado el método crearHebraProcesadora() que devolverá una subclase de la clase
HebraProcesadoraBase. La clase HebraProcesadoraBase apenas tiene funcionalidad
implementada pero nos sirve para guiar el desarrollo del componente y establecer unos
métodos genéricos. Como único parámetro de su constructor se le pasa una instancia del
componente del que va a procesar los eventos (el mismo que la está creando).

En el proceso de desarrollo deberá sobrescribirse el método run() que contendrá el código


que se ejecutará dentro de la hebra. Aparte dispone de los siguientes métodos:

" obtenerEventosColaRecepcion(): Devuelve un array que contiene todos los eventos que
hay en el momento de la llamada en la cola de recepción del componente. Este
método se usa normalmente en le proceso inicial de sincronización para examinar
los eventos existentes en busca de una respuesta de sincronización.
"
" leerSiguienteEvento(): Nos devuelve el siguiente evento disponible para ser procesado.
Si no hay ninguno disponible, quien lo llamó quedará bloqueado hasta que lo haya.
"
" iniciarHebra(): Mediante una llamada a este método se inicia la ejecución de la hebra.
Este método no tendrá que ser llamado cuando se desarrolla un componente a
partir del componente genérico DComponenteBase que ya será el quien de forma
automática lo llame cuando sea necesario.

Proyecto Fin de Carrera | 180


8.3. Clases captadoras

Los eventos que genera una clase captadora para notificarnos acciones del usuario sobre
la clase captadora tienen un nombre coincidente con el patrón DJxxxEvent. Las xxx
denotan la clase captadora que los generan.

Aparte de recoger los eventos que generan debe de haber alguna forma de notificarles
esos para que actualicen su estado (como se describe en la sección de diseño dentro del
apartado de eventos distribuidos). Esa notificación se realiza pasándoles el evento que
han generado con anterioridad (normalmente una vez haya sido recibido desde el
JavaSpace) a través de su método porcesarEvento(). El estado se actualiza después de
recibir la notificación y no antes puesto que se ha implementado un algoritmo pesimista.

La construcción de las clases captadoras ha sido bastante complicada, y únicamente


posible gracias a que los componentes gráficos de SWING no están implementados en
código nativo sino en código Java. Podemos acceder al código fuente de cualquier clase
de las que nos proporciona SUN en el archivo src.jar situado normalmente en la carpeta
raíz de la JDK.
Pasamos a detallar cada una de las clases captadoras implementadas y lo relacionado
con ellas:

Como primer paso vamos a mostrar una tabla indicando el tipo de eventos que genera
cada clase captadora para notificarnos mediante un DJListener de las acciones que vaya
realizando el usuario sobre dicha captadora.

Proyecto Fin de Carrera | 181


COMPONENTE EVENTO
DJList DJListEvent
DJComboBox DJComboBoxEvent
DJButton DJButtonEvent
DJToggleButton DJToggleButtonEvent
DJCheckBox DJCheckBoxEvent
DJTextField DJTextFieldEvent
DJTree DJTreeEvent
DJMenu DJMenuEvent
DJMenuItem DJMenuItemEvent
Tabla 8.1: Clases captadoras y eventos asociados

Ahora entramos más en profundidad en su comportamiento interno explicando los eventos


que generan a causa de la interacción (notificados mediante un DListener). Al lado del
nombre coloquial del componente aparece entre paréntesis el nombre de la clase en la
que se implementa la clase captadora. Cada clase captadora generará una clase diferente
evento. En la definición de la clase del evento se podrán observar una serie de variables
miembro de tipo static que definen los diferentes tipos de un evento. Por ejemplo para la
lista solo hay un tipo de evento que es CAMBIO_POSICION:

Lista (DJList):

Este componente genera sus notificaciones en forma de un evento del tipo DJListEvent.
Su diagrama UML es el siguiente:

Proyecto Fin de Carrera | 182


Ilustración 85: Diagrama de clases para
DJListEvent

Campos disponibles en el evento que genera el componente:

Tipo de evento Campos disponibles

CAMBIO_POSICION posicion
tipo

Tabla 8.2: Eventos disponibles para DJTreeEvent DJListEvent

Comentarios de los tipos de evento.

" CAMBIO_POSICION: Mensaje enviado cuando se cambia el elemento


seleccionado de la lista. En el campo posicion tendremos disponible la nueva
posición del elemento seleccionado en la lista.

El resto de campos serán usados por el componente replicado que usa esta clase
captadora.

Proyecto Fin de Carrera | 183


Dlistener
La interfaz definida como DListener en este componente se llama DJListListener.
Diagrama UML

Ilustración 86: Diagrama de clases para


DJListListener

Lista desplegable (DJComboBox):

Este componente genera sus notificaciones en forma de un evento del tipo


DJComboBoxEvent. Su diagrama UML es el siguiente:

Ilustración 87: Diagrama de clases para DJComboBoxEvent

Proyecto Fin de Carrera | 184


Campos disponibles en el evento que genera el componente:

Tipo de evento Campos disponibles

CAMBIO_SELECCION_LISTA seleccionLista
tipo

ABIERTO Ningún campo disponible

CERRADO Ningún campo disponible

SELECCIONADO itemSeleccionado
tipo

Tabla 8.3: Eventos disponibles para DJComboBoxEvent

Comentarios de los tipos de evento.

" CAMBIO_SELECCIÓN_LISTA: Mensaje enviado cuando al mover el ratón sobre la


lista (debe haberse abierto con anterioridad) cambia el elemento resaltado. El
campo seleccionLista contendrá el índice del nuevo elemento a resaltar.
" ABIERTO: Mensaje enviado se pulsa sobre el botón del componente estando la
lista en estado oculto.
" CERRADO: Mensaje enviado se pulsa sobre el botón del componente estando la
lista mostrada.
" SELECCIONADO: Mensaje enviado se pulsa sobre uno de los elementos de la
lista produciendo la selección de la misma. En el campo itemSeleccionado se
podrá encontrar el índice del elemento que ha sido seleccionado.

DListener
La interfaz definida como DListener en este componente se llama DJComboBoxListener.
Diagrama UML

Proyecto Fin de Carrera | 185


Ilustración 88: Diagrama de clases para DJComboBoxListener

Botón (DJButton):

Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo
DJButtonEvent. Su diagrama UML es el siguiente:

Proyecto Fin de Carrera | 186


Ilustración 89: Diagrama de clases para DJButtonEvent

Campos disponibles en el evento genera:

Tipo de evento Campos disponibles

PRESIONADO tipo

SOLTADO tipo

Tabla 8.4: Eventos disponibles para DJButtonEvent

Comentarios de los tipos de evento.

" PRESIONADO: Mensaje enviado cuando se pulsa el botón con el botón izquierdo
del ratón.
" SOLTADO: Mensaje enviado cuando se suelta el botón izquierdo del ratón
anteriormente pulsado.

DListener
La interfaz definida como DListener en este componente se llama DJButtonListener.
Diagrama UML

Proyecto Fin de Carrera | 187


Ilustración 90: Diagrama de clases para
DJButtonListener

Botón toggle (DJToggleButton):

Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo
DJToggleButtonEvent. Su diagrama UML es el siguiente:

Ilustración 91: Diagrama de clases para DJToggleButtonEvent

Proyecto Fin de Carrera | 188


Campos disponibles en el evento generado:

Tipo de evento Campos disponibles

PRESIONADO tipo

SOLTADO tipo

Tabla 8.5: Eventos disponibles para DJToggleButtonEvent

Comentarios de los tipos de evento.

" PRESIONADO: Mensaje enviado cuando se pulsa el botón toggle con el botón
izquierdo del ratón.
" SOLTADO: Mensaje enviado cuando se suelta el botón izquierdo del ratón
anteriormente pulsado.

DListener
La interfaz definida como DListener en este componente se llama
DJToggleButtonListener.
Diagrama UML

Ilustración 92: Diagrama de clases para DJToggleButtonEvent

Check box (DJCheckBox):


Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo
DJCheckBoxEvent. Su diagrama UML es el siguiente:

Proyecto Fin de Carrera | 189


Ilustración 93: Diagrama de clases para DJCheckBoxEvent

Campos disponibles del evento generado:

Tipo de evento Campos disponibles

PRESIONADO tipo

SOLTADO tipo

Tabla 8.6: Eventos disponibles para DJTreeEvent DJCheckBoxEvent

Comentarios de los tipos de evento.

" PRESIONADO: Mensaje enviado cuando se pulsa la checkbox con el botón


izquierdo del ratón.
" SOLTADO: Mensaje enviado cuando se suelta el botón izquierdo del ratón
anteriormente pulsado.

Proyecto Fin de Carrera | 190


DListener
La interfaz definida como DListener en este componente se llama DJCheckBoxListener.
Diagrama UML

Ilustración 94: Diagrama de clases para


DJCheckBoxListener

Campo de texto (DJTextField):

Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo
DJTextFieldEvent. Su diagrama UML es el siguiente:

Proyecto Fin de Carrera | 191


Ilustración 95: Diagrama de clases para
DJTextFieldEvent

Campos disponibles en los eventos generados:

Tipo de evento Campos disponibles

INSERT contenido
p1
tipo

REMOVE p1
p2
tipo

REPLACE contenido
p1
p2
tipo

Tabla 8.7: Eventos disponibles para DJTextFieldEvent

Comentarios de los tipos de evento.

Proyecto Fin de Carrera | 192


" INSERT: Mensaje enviado para indicar que se ha insertado un texto en una
determinada posición. La posición en la que se inserta es la indicada por el campo
p1 y el texto insertado el indicado en el campo contenido.
" REMOVE: Mensaje enviado para indicar que se va a eliminar una porción del texto.
Esa porción será el rango indicado por las posiciones de los campos p1 y p2.
" REPLACE: Mensaje enviado para indicar que una porción del texto va a ser
sustituido por otro texto. La porción de texto que desaparecerá será la situada en el
rango situado desde la posición indicada en el campo p1 hasta la posición p1 + p2.
En este caso p2 indica la longitud del texto que desaparecerá. El nuevo texto que
aparecerá en su lugar será el indicado en el campo contenido.

DListener
La interfaz definida como DListener en este componente se llama DJTextFieldListener.
Diagrama UML

Ilustración 96: Diagrama de clases para


DJTextFieldListener

Árbol (DJTree):

Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo DJTreeEvent.

Proyecto Fin de Carrera | 193


Su diagrama UML es el siguiente:

Ilustración 97: Diagrama de clases para


DJTreeEvent

Campos disponibles

Tipo de evento Campos disponibles

APERTURA_CIERRE path
tipo

SELECCION path
tipo

Tabla 8.8: Eventos disponibles para DJTreeEvent

Comentarios de los tipos de evento.

" APERTURA_CIERRE: Mensaje enviado cuando se abre o cierra un nivel. Una


apertura o cierre no tiene por qué coincidir con el cambio el ítem seleccionado en
ese momento. En el campo path tenemos la secuencia de nodos del camino desde
la raíz hasta el nodo que ha cambiado su estado de abierto a cerrado o viceversa.
Esta secuencia de nodos se expresa de forma numérica. Ver en el Apéndice B

Proyecto Fin de Carrera | 194


una explicación de cómo se realiza la traducción desde los objetos que conforman
el camino a una secuencia numérica que es la que se envía.
" SELECCIÓN: Mensaje enviado cuando se cambia el ítem seleccionado. En el
campo path tenemos la secuencia de nodos del camino desde la raíz hasta el
nuevo nodo seleccionado. Esta secuencia de nodos se expresa de forma numérica.
Ver en el Apéndice B una explicación de cómo se realiza la traducción desde los
objetos que conforman el camino a una secuencia numérica que es la que se
envía.

DListener
La interfaz definida como DListener en este componente se llama DJTreeListener.
Diagrama UML

Ilustración 98: Diagrama de clases para


DJTreeListener

Menú (DJMenu)
Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo DJMenuEvent.
Su diagrama UML es el siguiente:

Proyecto Fin de Carrera | 195


Ilustración 99: Diagrama de clases para DJMenuEvent

Campos disponibles

CAMBIO_ESTADO path
tipo

Comentarios de los tipos de evento.

" CAMBIO_ESTADO: Mensaje enviado cuando cambia el estado de este menú. En


el campo path tendremos un descriptor (secuencia de elementos desde el menú
que ha cambiado de estado hasta el menú raíz de la barra de menú) de la nueva
selección del menú en un array de enteros (ver Apéndice A) que posteriormente
nos servirá para reconstruir de forma aparente esa descripción.

DListener
La interfaz definida como DListener en este componente se llama DJMenuListener.

Diagrama UML

Proyecto Fin de Carrera | 196


Ilustración 100: Diagrama de clases para DJMenuListener

Dispone un único método que recibe un evento con el campo path establecido.

Item (DJMenuItem)
Evento manejado
Este componente genera sus notificaciones en forma de un evento del tipo
DJMenuItemEvent. Su diagrama UML es el siguiente:

Ilustración 101: Diagrama de clases para


DJMenuItemEvent

Campos disponibles

CAMBIO_ESTADO path
tipo

Comentarios de los tipos de evento.

Proyecto Fin de Carrera | 197


" CAMBIO_ESTADO: Mensaje enviado cuando cambia el estado de este item. En el
campo path tendremos un descriptor (secuencia de elementos desde el ítem que
ha cambiado de estado hasta el menú raíz de la barra de menú) de la nueva
selección del menú en un array de enteros (ver Apéndice A) que posteriormente
nos servirá para reconstruir de forma aparente esa descripción.

DListener
La interfaz definida como DListener en este componente se llama DJMenuItemListener.
Diagrama UML

Ilustración 102: Diagrama de clases para


DJMenuListener

Dispone un único método que recibe un evento con el campo path establecido.

Proyecto Fin de Carrera | 198


8.4. Componentes implementados listos para usarse

Los componentes que se han diseñado para ser usados en aplicaciones futuras o como
subcomponentes de componentes que se diseñen se van a catalogar en dos tipos. Por un
lado tendremos aquellos que hacen uso de una clase captadora y por otro los que no la
usan.

Componentes que hacen uso de una clase captadora

A continuación se muestran aquellos componentes que se han construido usando una


clase captadora:

" DILista. Clase que hace uso de la clase captadora DJList. Esta lista ya trae
incorporada las barras de scroll para desplazarse por los elementos cuando estos
no entran todos en la parte visible de la lista. El comportamiento distribuido que
implementa es el siguiente:
" Selección de elementos de la lista
" Adición y sustracción de elementos de la lista

A la hora de inicializar el componente existe la posibilidad de elegir entre un modo


dinámico y otro estático. El modo dinámico es el que se ha comentado, en el que
añadir y eliminar elementos de la lista es un comportamiento distribuido. En el
modo estático añadir o eliminar un elemento se hará de forma local sin ser
notificado a ninguna instancia. Debemos tener cuidado al usar el modo estático ya
que con facilidad podremos llegar a un estado inconsistente del componente.

" DIComboBox. Clase que hace uso de la clase captadora DJComboBox. El


comportamiento distribuido que implementa es el siguiente:
" Apertura y cierre de la lista
" Resaltado de los elementos de la lista conforme el ratón se mueve sobre
ellos
" Selección de un elemento de la lista (que conllevará el cierre de la lista).

Proyecto Fin de Carrera | 199


" DIButton. Clase que hace uso de la clase captadora DJButton. El comportamiento
distribuido que implementa es el siguiente:
" Pulsación y soltado del botón

" DIToggleButton. Clase que hace uso de la clase captadora DJToggleButton. El


comportamiento distribuido que implementa es el siguiente:
" Pulsación y soltado del botón

" DICheckBox. Clase que hace uso de la clase captadora DJCheckBoxButton. El


comportamiento distribuido que implementa es el siguiente:
" Pulsación y soltado de la checkbox.

" DITextField. Clase que hace uso de la clase captadora DJTextField. El


comportamiento distribuido que implementa es el siguiente:
" Inserción de texto en el campo de texto.
" Eliminación de texto del campo de texto.

" DITree. Clase que hace uso de la clase captadora DJTree. El comportamiento
distribuido que implementa es el siguiente:
" Apertura y cierre de niveles del arbol.
" Selección de un elemento del arbol.

Estos componentes tienen un método que nos puede interesar, crearDJListener(). Este
método es llamado por el componente en su inicialización para obtener el DJListener que
se va a encargar de procesar los eventos que genere la clase captadora. Normalmente
este comportamiento será el envío del evento generado. Si nos interesa que eso no sea
así podemos sobrescribir dicho método para devolver un listener personalizado y de esa
forma hacer el procesamiento que desee el programador.

Proyecto Fin de Carrera | 200


El caso de los menús (menús, ítems de menú y barra de menús) es algo especial. En
lugar de crear un componente haciendo uso de las clases captadoras diseñadas se ha
dotado de funcionalidad propia a la clase captadora. Esto es así debido a que por la forma
de funcionamiento de los menús no se podría crear haciendo uso del componente base
DComponenteBase. Un poco más adelante se explican en profundidad en un apartado
dedicado a ellos.

Componentes que no hacen uso de una clase captadora

En esta sección describiremos aquellos componentes que no hacen uso de una clase
captadora para implementar su comportamiento.

" DIChat. Este componente nos permitirá chatear con los demás usuarios que haya
conectados. Su funcionamiento es tan simple como escribir un texto en el campo
destinado a ello y pulsar sobre el botón Enviar. En la ventana de salida de
mensajes, cada mensaje aparecerá precedido por el nombre del usuario que lo ha
escrito. El nombre irá encerrado entre paréntesis como se puede ver en la imagen
siguiente:

Proyecto Fin de Carrera | 201


" DICambioRol. Es un componente que nos indica el rol que tenemos en cada
momento y cambiar a otro rol si tenemos permitido más de uno.

Para cambiar de rol solo deberemos escoger un rol de la lista y pulsar sobre el
botón Cambiar.

" DIEtiquetaRolActual. Este componente solo nos muestra información acerca del
rol que estamos desempeñando en cada momento:

" DlistaUsuariosConectados. Este componente nos permite ver qué usuarios están
conectados en cada momento:

" DlistaUsuariosConectadosInfoRol. Este componente es como el anterior con la


salvedad que además nos informa el rol que está desempeñando cada usuario:

Proyecto Fin de Carrera | 202


" DIArbolUsuariosConectados. Este componente nos muestra qué usuarios están
conectados en un instante dado al sistema clasificados por rol:

" DlistaUsuariosConectadosRol. Este componente nos muestra qué usuarios


están conectados y desempeñando el mismo rol que nosotros:

Proyecto Fin de Carrera | 203


• Arbol de Documentos (DIArbolDocumentos). Este componente nos permite
visualizar los documentos compartidos a los que un usuario tiene permisos de
acceso en forma de árbol de directorios. El aspecto del árbol de documentos sería:

Este componente permite realizar una serie de acciones sobre los documentos
mostrados por éste. Las posibles acciones son:

• Agregar un carpeta o documento.


• Buscar un fichero o carpeta dentro de árbol.
• Cambiar la metainformación de un documento o directorio.
• Eliminar un documento o carpeta.
• Comprobar si existe un documento.
• Obtener la metainformación del elemento seleccionado.
• Imprimir un documento.
• Guardar una copia local de un documento.
• Mover un documento de una ubicación a otra, mediante Drag&Drop.

La comunicación con el resto de réplicas del componente se realiza mendiante el


envío de notificaciones en forma de un evento del tipo DfileEvent.

Proyecto Fin de Carrera | 204


Los campos disponibles para el evento son los siguientes:

Tipo de evento Campos Descripción


disponibles
NOTIFICAR_INSERTAR_FICHERO path Mensaje enviado cuando se
fichero inserta un nuevo fichero en el
padre sistema
RESPUESTA_INSERTAR_FICHERO res Mensaje enviado para confirmar la
correcta inserción de un fichero
NOTIFICAR_ELIMINAR_FICHERO fichero Mensaje enviado cuando se
elimina un fichero en el sistema
RESPUESTA_ELIMINAR_FICHERO res Mensaje enviado para confirmar el
correcto borrado de un fichero
NOTIFICAR_MODIFICACION_FICHERO fichero, Mensaje enviado cuando se
path modifica la metainformación de un
fichero
RESPUESTA_MODIFICACION_FICHERO res Mensaje enviado para confirmar la
correcta modificación de la
metainformación de un fichero
SINCRONIZACION - Mensaje enviado para sincronizar
el árbol
RESPUESTA_SINCRONIZACION fichero, path Mensaje de respuesta a la
sincronización
EXISTE_FICHERO fichero Mensaje enviado para comprobar
si existe un fichero
RESPUESTA_EXISTE_FICHERO res Respuesta a la solicitud de
confirmación de existencia de un
determinado fichero.

Tabla 8.9: Tipos de evento para DFileEvent

Proyecto Fin de Carrera | 205


El proceso que se sigue para “actualizar” el árbol de documentos es el siguiente:

1. Se realiza algún tipo de acción sobre los documentos compartidos (creación,


eliminación, modificación, etc,). Por ejemplo, cambiar el nombre a un
documento.

2. A través del cliente de ficheros, se envía al servidor de ficheros un evento


del tipo: NOTIFICAR_ACCIÓN_FICHERO.

3. El servidor realiza las acciones necesarias de acuerdo con el evento


recibido. Por ejemplo, si le hemos cambiado el nombre a un documento,
cambiar el nombre del documento en sus sistema de archivos local y en la
base de datos.

4. El servidor responde con un evento RESPUESTA_ACCIÓN_FICHERO


indicando en el campo res si la acción ha sido llevada con éxito o no.

5. Si la respuesta del servidor es de éxito en la operación:

a) El árbol de documentos envía un evento


NOTIFICAR_ACCIÓN_FICHERO a todas sus réplicas, incluido él mismo.
b) Las réplicas reciben el evento NOTIFICAR_ACCIÓN_FICHERO y
actúan en consecuencia. Por ejemplo, cambiar el nombre del nodo
asociado al documento.

El siguiente diagrama de colaboración muestra de forma detallada el proceso


descrito arriba:

Proyecto Fin de Carrera | 206


Ilustración 103: Diagrama de secuencia para ArbolDocumentos

• Visualizador (DIViewer). Este componente nos permite visualizar imágenes de


forma compartida. El aspecto del lienzo seria el siguiente:

Como podemos observar, el visualizador no es más que un panel sobre el que se


dibuja la página actual del documento. Dado que la dimensión del documento
puede ser mayor que el tamaño del panel, el lienzo incorpora unas barras de

Proyecto Fin de Carrera | 207


desplazamiento para que se pueda acceder a todo el documento.
Cuando se inicializa el componente, éste se sincroniza con el resto de réplicas de
sí mismo, cargando la imagen compartida.
Este componente nos permite cargar una imagen en el visualizador. La imagen
cargada se distribuye entre el resto de réplicas del componente, con el objetivo de
que todos las réplicas muestren la misma imagen.

La comunicación con el resto de réplicas del componente se realiza mediante el


envío de notificaciones en forma de un evento del tipo DJViewerEvent.
Los campos disponibles para el evento son los siguientes:

Tipo de evento Campos Descripción


disponibles
CARGA imagen Mensaje enviado cuando se
carga una nueva imagen.
SINCRONIZACION - Mensaje enviado para
sincronizar
RESPUESTA_SINCRONIZACION imagen Mensaje de respuesta a la
sincronización, se envían la ip
y el puerto por los cuales se
recibirá el documento vía RMI

Tabla 8.10: Tipos de evento para DJViewerEvent

• Lienzo (DILienzo). Este componente nos permite realizar anotaciones sobre un


documento compartido de forma colaborativa. El aspecto del lienzo seria el
siguiente:

Proyecto Fin de Carrera | 208


Como podemos observar, el lienzo no es más que un panel sobre el que se dibuja
la página actual del documento. Dado que la dimensión del documento puede ser
mayor que el tamaño del panel, el lienzo incorpora unas barras de desplazamiento
para que se pueda acceder a todo el documento.

Este componente permite realizar una serie de acciones sobre la página actual del
documento. Las posibles acciones son:
• Agregar una anotación a la página.
• Seleccionar una anotación.
• Eliminar una anotación.
• Deshacer la ultima anotación.
• Cambiar el estilo de anotación (elipse, rectángulo, texto, etc.).
• Cambiar el color de las anotaciones.
• Cambiar la página del documento.
• Eliminar todas las anotaciones de la página actual.

La comunicación con el resto de réplicas del componente se realiza mediante el


envío de notificaciones en forma de un evento del tipo DJLienzoEvent.

Los campos disponibles para el evento son los siguientes:

Proyecto Fin de Carrera | 209


Tipo de evento Campos Descripción
disponibles
NUEVA_ANOTACIÓN anotaciones Mensaje enviado cuando se
, realiza una nueva anotación
num_pagina
LIMPIEZA_LIENZO num_pagina Mensaje enviado cuando se
limpian los comentarios de una
página del documento
DESHACER - Mensaje enviado cuando se
deshace
BORRAR_ANOTACION numAnotaci Mensaje enviado cuando se borra
on una anotación
REHACER - Mensaje enviado cuando se
modifica la metainformación de un
fichero
CAMBIO_PAGINA nuevaPagin Mensaje enviado para notificar el
a cambio de la página
SINCRONIZACION - Mensaje enviado para sincronizar
RESPUESTA_SINCRONIZACION ip, puerto Mensaje de respuesta a la
sincronización, se envían la ip y el
puerto por los cuales se recibirá el
documento vía RMI

Tabla 8.11: Tipos de evento par DJLienzoEvent

Proyecto Fin de Carrera | 210


Diagrama de clases:

Ilustración 104: Diagrama de clases para el subsistema

Aspecto de los componentes según permiso

Algunos de los componentes creados cambian su aspecto dependiendo de que el usuario


tenga o no permiso de escritura sobre ellos. En la siguiente tabla se muestran esos
componentes así como sus diferencias de aspecto. Los componentes que no aparecen en
la lista es porque su aspecto no varía en función de los permisos.

Proyecto Fin de Carrera | 211


Componente Con p. escritura Sin p.escritura
DILista

DIComboBox

DIButton

DIToggleButton

DICheckBox

DITextField

DIChat

JMenu

JMenuItem

Tabla 8.12: Aspecto de los componentes gráficos según sus permisos

Proyecto Fin de Carrera | 212


8.5. Menús

La selección del menú se maneja de forma global mediante la clase


DMenuSelectionManager. En la implementación actual se limita a la existencia de un
menú por aplicación.

Barra de menú

La barra de menú es un componente replicado (DComponente) aunque su funcionalidad


distribuida es casi nula. Se encarga de restablecer el menú a un estado válido si el
usuario que posee la selección del menú sale de la aplicación sin haberlo cerrado antes.
De esta forma evitamos que el menú se quede bloqueado. Respecto a una barra de menú
convencional añade la peculiaridad de que tiene una zona en la que se puede ver qué
usuario es el que actualmente está actuando sobre el menú (siempre que haya alguno).
En la figura podemos ver que el usuario LooPer es el actual poseedor de la selección.

Menú

Se denomina menú a cada uno de los botones que hay en la barra de menú sobre los que
si se pulsa el botón del ratón se abre un menú popup con las opciones que contiene. Un
menú se puede añadir a otro menú con lo que conseguiremos un submenú que podrá
contener sus propias opciones.

Si no hay ningún menú abierto para abrir uno será necesario pulsar el botón izquierdo del
ratón sobre alguno de los menús principales (los situados en la barra de menú). Una vez
abierto alguno sólo será necesario situar el puntero del ratón sobre algún menú o

Proyecto Fin de Carrera | 213


submenú para abrir su ventana popup asociada. Para cerrar el menú principal abierto será
necesario pulsar de nuevo el botón izquierdo del ratón sobre él.

Ítem

Los ítems de un menú son los elementos que se añaden a un menú y sobre los que se
puede pulsar para ejecutar alguna acción (si la tiene asociada). A los ítems del menú se
les puede asociar un LListener y/o un LUListener para ser notificados cuando se pulse
sobre él.

Proyecto Fin de Carrera | 214


8.6. Sincronización de componentes

En este apartado se va a explicar cómo se desarrolla la sincronización de los


componentes de forma conceptual y las implementaciones realizadas. Existen
componentes que pueden no necesitar de sincronización como es el caso del
componente DIChat desarrollado.

Cuando un usuario arranca una aplicación distribuida ésta deberá sincronizar sus
componentes con los de los demás usuarios para que queden en un estado consistente.

En el proceso de inicialización el primer paso de la sincronización es que los


componentes envíen una petición conforme desean sincronizarse respecto a los demás
componentes. Esta petición se envía en forma de evento de tipo SINCRONIZACIÓN en
todos los componentes implementados. Los componentes no deberán estar al tanto de
cómo va el proceso de inicialización de la aplicación para enviar la petición. Será el
DConector el que, mediante la llamada al método sincronizar() de cada componente, el que
les indique que deben enviar la petición de sincronización.

Pasado un tiempo prudencial (que deberá establecerse por el programador) el DConector


iniciará las hebras procesadoras de cada componente. Cada hebra en su inicio, antes de
entrar en el bucle de recepción de eventos, deberá comprobar los eventos que se han
recibido desde que se envió la petición, buscando si se ha recibido alguna respuesta a la
petición enviada (evento del tipo RESPUESTA_SINCRONIZACION en la implementación
realizada). Si no se encuentra ninguna es que no hay ningún otro usuario activo en ese
momento o que la hebra procesadora no está correctamente programada. En el caso de
haberla, la procesaremos y actualizaremos el estado del componente. Esta respuesta
tendrá un valor numérico en el campo ultimoProcesado que nos indica cual había sido el
último evento procesado por el componente que nos envió la respuesta a nuestra petición
en el momento de realizar dicho envío. Aquellos eventos que tenemos en la cola de
recepción con un número de secuencia mayor a ultimoProcesado de ser procesados de la
forma habitual por la hebra procesadora ya que son modificaciones posteriores del estado

Proyecto Fin de Carrera | 215


del componente respecto del que hemos establecido con la información recibida. De este
modo garantizamos que el componente sigue en un estado consistente a pesar de que los
demás usuarios (en caso de que los hubiera) hayan estando interactuando con el
componente mientras nosotros realizábamos la sincronización.

La hebra procesadora de cada componente deberá estar preparada para responder a las
peticiones de sincronización por parte de otros componentes enviándoles su estado
actual.

Los componentes que se han implementado para el uso posterior por el programador
podrán usarse como parte de un componente más complejo (en los ejemplos de
desarrollo de componentes se podrá ver cómo). Cuando este componente complejo
reciba una petición de sincronización probablemente deba incluir en su información de
estado actual el estado del componente que forma parte de él. Para este fin cada
componente de los ofertados tiene los métodos obtenerInfoEstado() y procesarInfoEstado().
Mediante el primero obtenemos un evento con la información del estado actual del
componente. Dicho evento normalmente será añadido al evento de respuesta de
sincronización del componente complejo. Cuando el componente que se está
sincronizando reciba una respuesta que contenga el evento que se obtuvo con el método
obtenerInfoEstado() podrá pasárselo el componente correspondiente mediante el método
pocesarInfoEstado() para que actualice su estado. Debido a la forma de funcionamiento de la
sincronización es aconsejable implementar unos métodos iguales o similares a estos si
tenemos en mente que nuestro componente sea usado posteriormente como parte de otro
futuro componente desarrollado.

Proyecto Fin de Carrera | 216


8.7. Telepunteros (Gestor de Mouses Remotos)

Denominaremeos Gestor de Mouses Remotos (GMR) al componente encargado de


gestionar y mostrarnos los punteros de los demás participantes de la aplicación
(telepunteros). Este componente también es un componente replicado implementando la
interfaz DComponente directamente.

Antes de entrar en detalles debemos tener muy claro que si se añade a una aplicación la
funcionalidad de telepunteros la ventana en la que se muestran no deberá poderse
cambiar de tamaño ya que ello podría llevarnos con facilidad a inconsistencias de las
posiciones de los telepunteros.

El GMR mantiene en una estructura interna de información sobre los demás participantes
que se va actualizando conforme se van recibiendo notificaciones cuando se mueven sus
punteros. Cada vez que se actualiza la posición del puntero de alguno de los usuarios se
vuelven a pintar los punteros para reflejar dicho cambio.
Para la implementación de este gestor se plantearon dos problemas, los cuales se
comentan a continuación así como la solución adoptada ante el problema:

¿Cómo captar los eventos locales?

Está claro que debemos captar los movimientos de nuestro ratón para notificárselo a los
demás participantes. Esta captación presenta un problema.
Alguien podría pensar que una forma de resolverlo sería añadir un lístener a cada uno de
los componentes de la aplicación para captar esos movimientos. Esta solución es
demasiado compleja dado que tendríamos que ir componente por componente añadiendo
un nuevo listener.
Otra opción barajada sería añadir un listener al Glass Pane (ver explicación en el
siguiente problema) del JFrame y desde ahí notificar los cambios. El problema de esta
solución es que si se capta el evento de ratón en el Glass Pane dicho evento no llega a
los componentes de la aplicación por lo que se anularía totalmente la interacción.
Finalmente se adoptó como solución sustituir la cola de eventos del sistema por una

Proyecto Fin de Carrera | 217


personalizada. De esta forma en la nueva cola de eventos captaremos los eventos de
movimiento de ratón que tanto nos interesan.

¿Dónde pintar los punteros de los demás usuarios?

Se debía buscar un lugar donde pintar los botones. De todas las posibilidades barajadas
se ha optado por usar el Glass Pane como lugar para pintar dichos punteros. El Glass
Pane es un componente transparente que se sitúa sobre todos los demás componentes.
En la siguiente figura podemos ver su localización:

Ilustración 105: Esquema del Glass Pane

Por tanto al estar sobre cualquier otro componente aparecerá siempre en primer plano.
En la implementación actual se restringe el uso de telepunteros a un único Frame.

Proyecto Fin de Carrera | 218


9. Manual del desarrollador

A lo largo de las sucesivas secciones se realizarán distintos ejemplos ilustrativos del


proceso de desarrollo a seguir para realizar cualquier tipo de aplicación y posteriormente
adaptarla como plugin para la plataforma. Así mismo, se darán distintos consejos y guías
para que el resultado final de la aplicación a crear sea consecuente con los esquemas de
diseño del resto del sistema, evitando además que se produzcan distintas eventualidades
que puedan llevar a la inestabilidad del sistema completo.

Realizaremos una aplicación, aumentando su complejidad sucesivamente hasta abarcar


la mayor cantidad de posibilidades que provee el Framework. Se recomienda a los
desarrolladores que sigan las siguientes secciones en orden para aumentar
progresivamente su experiencia en el uso del abanico de posibilidades que se proveen.

Fase 1: Creación del proyecto para el desarrollo del plugin


Antes de comenzar con el desarrollo de nuestro plugin, deberemos crear un proyecto
vacío con nuestro IDE favorito. En nuestro caso haremos uso de Netbeans en su versión
6.1. Tras la creación del proyecto vacío deberemos agregar las bibliotecas necesarias
para poder realizar el desarrollo completo. Éstas bibliotecas están localizadas en la
carpeta "bin/Framework/Needed_libs" del soporte físico adjunto. Podemos observar como
existe también en éste directorio una carpeta llamada "Resources" que no contiene
ninguna biblioteca. Ésta carpeta contiene una biblioteca de imágenes que pueden
servirnos como iconos para los componentes gráficos que desarrollemos. Todos éstos
componentes han sido seleccionados para que la interfaz gráfica que realice el
desarrollador tenga una apariencia homogénea con respecto al resto de la aplicación.
Ésta carpeta conviene también agregarla al proyecto o, al menos, al classpath, puesto
que la mayoría de los componentes gráficos ofertados los requieren para su correcto
funcionamiento.

Tras realizar las operaciones anteriores, nuestro proyecto debería quedar como en la
siguiente imagen (salvo los nombres del proyecto y del paquete por defecto creado por
Netbeans).

Ilustración 106: Visualización de los elementos


involucrados en el proyecto
En éste caso, la carpeta "Resources" ha sido agregada al classpath, y no directamente al
proyecto.

Fase 2: Ventana asociada al plugin


Crearemos una ventana que muestre los componentes gráficos de los que hagamos uso
para el desarrollo del plugin. Ésta ventana puede ser implementada con cualquier
biblioteca de desarrollo de interfaces gráficas existente en Java, incluyendo las bibliotecas
Swing, o mediante el componente gráfico DJFrame provisto por el marco de trabajo.
Puesto que se pretende mostrar la simplicidad de desarrollo se ha optado por el uso de
DJFrame. Para ello, simplemente crearemos una nueva clase llamada "VentanaPlugin"

Proyecto Fin de Carrera | 220


que herede de DJFrame. Crearemos también un constructor vacío. El código fuente de
ésta ventana se muestra a continuación.

package template_jdistframework;

import componentes.base.DJFrame;

public class VentanaPlugin extends DJFrame


{
public VentanaPlugin()
{
super(false, "");
}
}

Evidentemente, éste código se corresponde con una ventana vacía. En la siguiente


sección crearemos un componente gráfico para agregárselo a ésta ventana.

Fase 3: Componente gráfico para el plugin


Ésta fase del desarrollo será la más compleja, puesto que se deberá de crear un
componente gráfico para agregárselo a la ventana anteriormente creada. Éste
componente gráfico normalmente será un panel, al cuál agregaremos una serie de
componentes "hijo". Entre éstos componentes se encontrarán algunos que dispongan de
eventos distribuidos (Los proporcionados por las bibliotecas del marco de trabajo) o
eventos locales (Los proporcionados por las bibliotecas de Java, como Swing). Para llevar
a cabo todo lo que se muestra a continuación será necesario agregar un nuevo fichero a
nuestro proyecto que herede de JPanel.

Primero, agregaremos dos paneles, uno llamado "oeste" y otro llamado "centro". A ambos
paneles les asociaremos un layout del tipo "BorderLayout". Por ahora tendremos el
siguiente código para el panel:

package template_jdistframework;

Proyecto Fin de Carrera | 221


import javax.swing.JPanel;

public class PanelPlugin extends JPanel {


public PanelPlugin()
{
JPanel oeste = new JPanel(new BorderLayout());
JPanel centro = new JPanel(new BorderLayout());
}
}

A éstos componentes ahora le agregaremos un componente de chat y un arbol con los


usuarios conectados, ordenados por rol. El componente de chat lo agregaremos en el
panel "centro" y el de los usuarios lo agregaremos en el panel "oeste". La idea será crear
una interfaz gráfica parecida a la que se muestra a continuación:

Ilustración 107: Esquema gráfico del chat a desarrollar

Para agregar la lista de usuarios haremos uso del componente

Proyecto Fin de Carrera | 222


"ArbolUsuariosConectadosRol". Para agregar el chat, haremos uso del componente
"DIChat". Ambos componentes los provee el framework. El código anterior ahora quedaría
como sigue:

package template_jdistframework;

import componentes.gui.DIChat;
import componentes.gui.usuarios.ArbolUsuariosConectadosRol;

import javax.swing.JPanel;

import java.awt.BorderLayout;

public class PanelPlugin extends JPanel {


public PanelPlugin()
{
JPanel oeste = new JPanel(new BorderLayout());
JPanel centro = new JPanel(new BorderLayout());
ArbolUsuariosConectadosRol arbol = new
ArbolUsuariosConectadosRol("ListaUsuariosConectadosRol", true, null);

DIChat chat = new DIChat("chat", true, null);


oeste.add(arbol, BorderLayout.CENTER);
centro.add(chat, BorderLayout.CENTER);
}
}

En las creaciones de ambos componentes se han usado un nombre, el valor booleano


"true" y por último null. El significado de éstos parámetros se puede ver en profundidad en
la documentación del framework, pero de forma resumida se puede decir que la cadena
de texto representa al nombre del componente (debe estar dado de alta en el servidor de
metainformación), el valor booleano indica que queremos conectarnos de forma directa al
DConector (El "distribuidor" de eventos), y, por último, el valor null indica que éstos
componentes no tienen ningún componente padre que sea distribuido.

Proyecto Fin de Carrera | 223


Para mejorar la interfaz gráfica agregaremos una etiqueta que ponga "Usuarios" en el
panel oeste y una barra de herramientas para poder ampliar funcionalidad. También
agregaremos por fin los paneles creados al componente gráfico. El código será el
siguiente:

package template_jdistframework;

import componentes.gui.DIChat;
import componentes.gui.usuarios.ArbolUsuariosConectadosRol;

import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.Dimension;

public class PanelPlugin extends JPanel {


public PanelPlugin()
{
JPanel oeste = new JPanel(new BorderLayout());
JPanel centro = new JPanel(new BorderLayout());
ArbolUsuariosConectadosRol arbol = new
ArbolUsuariosConectadosRol("ListaUsuariosConectadosRol", true, null);
DIChat chat = new DIChat("chat", true, null);
oeste.add(new JLabel("Usuarios"), BorderLayout.NORTH);
oeste.add(arbol, BorderLayout.CENTER);
centro.add(new PanelControlChat(), BorderLayout.NORTH);
centro.add(chat, BorderLayout.CENTER);
this.setLayout(new BorderLayout());
this.add(centro, BorderLayout.CENTER);
this.add(oeste, BorderLayout.WEST);
}

private class PanelControlChat extends JPanel


{

Proyecto Fin de Carrera | 224


public PanelControlChat()
{
initialize();
}
private void initiliaze()
{
this.setSize(496, 39);
this.setPreferredSize(new Dimension(373, 39));
this.setMinimumSize(new Dimension(373, 39));
this.setLayout(new BorderLayout());
}
}
}

El resultado gráfico de éste código es el siguiente:

Ilustración 108: Imagen del chat

Con el código anterior ya podremos ver los distintos usuarios que están conectados, así
como recibir y enviar mensajería instantánea desde y hacia todos los usuarios

Proyecto Fin de Carrera | 225


conectados. Se puede agregar funcionalidad en la barra de herramientas para que se
puedan realizar videoconferencias, guardar conversaciones, cerrar la ventana de chat,
cambiar la fuente de las letras, etc. Un ejemplo del código fuente que tendríamos que
introducir para agregar videoconferencia a nuestro chat se muestra a continuación:

botonNuevaVC = new JButton(" ");


botonNuevaVC.setIcon(new ImageIcon("Resources/webcam.png"));
botonNuevaVC.setBorder(null);
botonNuevaVC.setBorderPainted(false);
botonNuevaVC.setToolTipText("Invitar a un usuario a iniciar una videoconferencia");
botonNuevaVC.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
String user = arbol.getUsuarioSeleccionado();

if (( user != null ) && ( !user.equals(DConector.Dusuario ) ) )


{
DJChatEvent ev = new DJChatEvent();
ev.tipo = new Integer(DJChatEvent.INICIAR_VC.intValue());

try {
ev.ipVC = InetAddress.getLocalHost().getHostAddress();
ev.receptores.add(new String(user));

chat.enviarEvento(ev);
}
catch (UnknownHostException e1)
{
JOptionPane.showMessageDialog(null,
"Ha ocurrido un error en la comunicación. Inténtelo mas tarde");
return;
}
}
});

Proyecto Fin de Carrera | 226


Evidentemente, éste código deberá ser integrado debidamente con el código fuente de la
barra de herramientas. Se puede ver como se ha hecho uso de una de los iconos
proporcionados por la colección de imágenes del framework. El ejemplo anterior es una
forma bastante clara de ver como dos componentes pueden interaccionar entre sí gracias
a los distintos métodos de cada uno de ellos y del envío de eventos.

Fase 4: Creación del plugin


Una vez hemos creado el componente gráfico asociado a nuestro plugin, deberemos de
agregarlo a nuestra ventana. Bastará con hacer un "setContentPane", poniendo como
panel contenedor el componente. Una vez hemos integrado los resultados de las dos
fases anteriores, deberemos implementar el plugin en sí. Para que la plataforma pueda
hacer uso del plugin creado, éste, necesariamente, deberá de implementar la clase
abstracta "DAbstractPlugin". Ésta clase tiene una serie de métodos que nos permiten
obtener una instancia, inicializar, ejecutar y parar un plugin. Además, tiene una serie de
variables de instancia que nos permiten configurar como se mostrará en la plataforma.

Comenzaremos creando la clase que implementa los métodos abstractos requeridos, pero
con todos ellos creados como "stubs". Para hacer ésto, agregaremos convenientemente
un nuevo fichero a nuestro proyecto al que llamaremos "Plugin" y que heredará de la
clase "DAbstractPlugin". La IDE se encargará de crear los métodos "stubs" por nosotros.

El código completo del plugin se muestra a continuación, y como se puede observar, es


absolutamente trivial su implementación.

public class Plugin extends DAbstractPlugin


{
private static final long serialVersionUID = -6310087937591625336L;
private VentanaPlugin ventanaChat = null;

public Plugin() throws Exception


{
super("chatplugin", false, PluginContainer.getPC(), "Chat", 1, "chat.jar", true);

Proyecto Fin de Carrera | 227


init();
}

@Override
public void init() throws Exception
{
versioningEnabled = true;
categoria = DAbstractPlugin.CATEGORIA_COMUNICACION;
descripcion = "Chat con videoconferencia integrada. Permite
mensajes privados y publicos";
ventanaChat = new VentanaPlugin();
ventanaChat.setResizable(true);
ventanaChat.pack();
ventanaChat.setSize(550, 430);
ventanaChat.setTitle(":: Chat - " + DConector.Dusuario + " ::");
ventanaChat.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
ventanaChat.setLocationRelativeTo(null);
}

@Override
public void start() throws Exception
{
ventanaChat.setVisible(true);
}

@Override
public void stop() throws Exception
{
ventanaChat.dispose();
}

@Override
public void enviarEvento(DEvent e)
{
DIChat chat = ventanaChat.obtenerChat();

Proyecto Fin de Carrera | 228


if (e.tipo.intValue() == DJChatEvent.MENSAJE_PRIVADO.intValue())
chat.enviarEvento(e);
else if (e.tipo.intValue() == DJChatEvent.INICIAR_VC.intValue())
chat.enviarEvento(e);
else
super.enviarEvento(e);
}
}

Como se puede observar, se ha creado un constructor donde se llama a la clase de la que


se hereda y se llama al método que inicializa el plugin. En cualquier plugin que
implementemos, ésto deberá hacerse tal cual aparece en el código mostrado. Los
parámetros con los que se llama al constructor de la clase superior son los siguientes:
Nombre del componente, Valor booleano que indica si queremos o no conexion directa
con el DConector (normalmente, por ser un plugin, aquí pondremos "false"), el
componente padre del plugin (Normalmente, por cuestiones de implementación,
pondremos siempre como padre del plugin la instancia en ejecución del contenedor de
plugins, es decir, de la clase "PluginContainer"), el nombre del plugin a mostrar en la
plataforma, la versión del plugin, el fichero jar donde se contendrá el plugin (se verá en la
siguiente sección) y una variable booleana que indique si el plugin aparecerá por defecto
o no en la lista de aplicaciones de la plataforma (Normalmente indicaremos "true", pero si
realizamos algún tipo de filtro de fichero o algún plugin que no tenga interfaz gráfica
propia y que tan solo aporte funcionalidad, entonces puede ser interesante poner ésto a
"false").

El método "init" se encargará de inicializar todas las variables de instancia del plugin. En
nuestro caso solo tendremos la variable de instancia asociada a la ventana. También
podremos, opcionalmente, asignar valores a ciertos parámetros de configuración del
plugin, como pueden ser la descripción, la categoría o si queremos o no tener un control
automático de versiones (para poder distribuir las nuevas versiones de nuestro plugin
entre los usuarios de la plataforma de una forma más rápida y sencilla). Es muy
importante, que se asigne siempre la operación por defecto al cerrarse la ventana a

Proyecto Fin de Carrera | 229


"ocultar", puesto que si ponemos "salir", entonces la plataforma se cerrará
completamente, si ponemos "dispose", entonces solo se podrá abrir una vez el plugin, y si
ponemos "no hacer nada", entonces no podremos cerrar la ventana.

El método "start" es el encargado de comenzar la ejecución del plugin. En nuestro caso,


comenzar la ejecución será equivalente a mostrar la ventana.

El método "stop" permite poner fin a la ejecución del plugin. En éste caso bastará con
hacer un "dispose" a la ventana. Hay que destacar que el método "stop" solo se llamará al
final de la ejecución de la plataforma, con que es válido descargar de memoria todos los
componentes o asignarlos a null y llamar al recolector de basura explícitamente, puesto
que en ningún caso, tras un "stop" se realizará un "start".

En nuestro caso, hemos tenido que reimplementar el método encargado de enviar un


evento, es decir, el método "enviarEvento". Éste método no es necesario implementarlo
normalmente (ya se encuentra implementado convenientemente en las clases
superiores), pero en éste caso, puesto que haremos control de versiones en el plugin y
además se requerirá capturar eventos y enviarlos al chat, entonces deberemos
seleccionar entre que componente será el receptor de cada evento, si el propio plugin o el
componente de chat. Para poder enviar los eventos al chat, deberemos de agregar
métodos a la clase "VentanaPlugin" y "PanelPlugin" que nos permitan obtener el
componente DIChat correspondiente (Se debe recordar que éste componente es una de
las variables de instancia de la clase "PanelPlugin" y que tiene como nombre "chat").

Fase 5: Integración del plugin en la plataforma


Ésta es quizás la fase más sencilla dentro del desarrollo del plugin. Una vez realizada la
implementación descrita en las anteriores fases, bastará con crear un fichero con
extensión .jar que contenga todos los ficheros creados hasta ahora. Para hacer ésto, en
Netbeans, bastará con pulsar en "Build>>Build Main Project". Ésto nos creará un fichero
.jar en la carpeta "dist" de nuestro proyecto. Netbeans, además, nos creará una carpeta
con las bibliotecas usadas por el proyecto, pero en nuestro caso, ésta carpeta deberemos
obviarla (No distribuirla junto al plugin), excepto en el caso en el que agreguemos

Proyecto Fin de Carrera | 230


bibliotecas externas a las proporcionadas por el framework.

Una vez poseamos el fichero .jar, lo copiaremos y pegaremos en la carpeta "plugin" que
hay dentro del directorio donde tengamos instalada la aplicación cliente. Si hemos usado
alguna biblioteca ajena al framework, deberemos situarla en la carpeta "lib", también
dentro del directorio donde esté instalado el cliente.

El fichero .jar que situemos en la carpeta "plugin" deberá tener el mismo nombre que
nosotros hayamos especificado en el código fuente del plugin (en nuestro caso el fichero
se llamará "chat.jar").

Una vez situados todos los ficheros en los lugares correspondientes, ejecutaremos la
plataforma para ver los resultados obtenidos. Veamos ahora una serie de capturas de
pantalla que ilustren ésto.

Ilustración 109: Pantalla principal

Proyecto Fin de Carrera | 231


Ilustración 110: Ventana del chat

Como se puede observar, el plugin nos aparece en la lista de aplicaciones disponibles y


además, si hacemos doble click sobre él nos muestra la ventana que hemos
implementado a lo largo de las fases anteriores. Si pasamos el ratón por encima del
nombre del plugin en la lista de aplicaciones de la plataforma se mostrará la descripción
que nosotros agregamos. La categoría del plugin no se muestra visualmente, aunque es
de gran utilidad para futuros desarrollos de la plataforma, donde los plugins se puedan
mostrar de forma ordenada (por ejemplo, en un árbol).

Se puede observar como la ventana tiene una barra de herramientas con diversas
características. Ésta barra de herramientas se puede ampliar o reducir tanto como
queramos en funcionalidad. El segundo botón de ésta barra, por ejemplo, tiene el mismo
código fuente que se mostró al final de la fase 3. El último botón se limita simplemente a
cerrar la ventana.

Si abrimos el gestor de plugins veremos como las características que nosotros pusimos al
configurar el plugin se muestran correctamente.

Proyecto Fin de Carrera | 232


Ilustración 111: Gestor de plugins

Para distribuir la versión inicial del plugin podremos, por ejemplo, subirlo como fichero a la
plataforma. Las sucesivas versiones, una vez que actualicemos el fichero .jar en uno de
los clientes se distribuirán automáticamente al resto (mostrando previamente un mensaje
de confirmación de descarga de la nueva versión).

Proyecto Fin de Carrera | 233


10. Apéndices

A. Casos de uso detallados

Los siguientes casos de uso son los identificados para el sistema. Algunos de ellos, tras
realizar el proceso de análisis y diseño, han pasado a formar parte de los casos de uso de
ciertos plug-ins (como el de chat o el de videoconferencia), aportados por defecto, y otros
se han asociado con el comportamiento general de la aplicación principal. El siguiente
listado tiene como objeto mostrar las principales características perseguidas en el proceso
de desarrollo del proyecto.

Nombre: Abrir Documento

Actor: Usuario

Descripción: El usuario abre un documento para su anotación

Iniciador: El usuario selecciona y escoge la opcion Abrir Documento

Precondiciones: 1. El documento seleccionado no es una carpeta

Postcondiciones: 1.
Flujo Normal: 3. El sistema muestra al usuario el documento en una nueva
ventana
4. Mientras el usuario no cierre la ventana
a. Si el usuario desea agregar una anotacion se inicia el
caso de uso Anotar Documento
b. Si el usuario desea eliminar una anotacion se inicia el
caso de uso Eliminar Anotacion Documento
c. si el usuario dese imprimir el documento se inicia el
caso de Uso imprimir documento
d. Si el usuario desea guardar el documento se inicia el
caso de uso Guardar Documento

Flujo Alternativo: 1. Si el documento no está soportado el sistema muestra un


mensaje al usuario indicándole si desea abrir el documento en
modo texto.
a. Si el usuario selecciona abrir en modo texto vamos al
paso 2. del flujo normal
b. En caso contrario termina el caso de uso

Excepciones: Si se produce algún error en la carga del documento el sistema muestra


un error

Incluye: Anotar Documento, Eliminar Anotacion Documento, Imprimir


Documento, Guardar Documento

Prioridad: Alta

Frecuencia de uso: Alta

Nombre: Anotar Documento

Actor: Usuario

Descripción: El usuario abre un documento para su anotación

Iniciador:

Precondiciones: 1. Esta ejecutandose el caso de uso Abrir Documento

Proyecto Fin de Carrera | 235


Postcondiciones: 1.

Flujo Normal: 1. El usuario dibuja la anotacion en el documento


2. El sistema pinta la anotacion en el documento, almacenado
además el usuario, el rol y la fecha de la anotacion y distribuye
el evento por la red.

Flujo Alternativo: 1.

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Alta

Nombre: Eliminar Anotación Documento

Actor: Usuario

Descripción: El usuario elimina una anotacion en un documento

Iniciador: El usuario selecciona una anotacion y pulsa el boton de eliminar


anotacion

Precondiciones: 1. Se está ejecutando el caso de uso Abrir Documento

Postcondiciones: 1. La anotacion es eliminada del documento

Flujo Normal: 1. El sistema elimina la anotacion y distribuye el evento por la red.

Proyecto Fin de Carrera | 236


Flujo Alternativo:

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Alta

Nombre: Guardar Documento

Actor: Usuario

Descripción: El usuario guarda los cambios realizados en las anotaciones de un


documento

Iniciador: El usuario escoge la opcion guardar documento

Precondiciones: 1. Se está ejecutando el caso de uso Abrir Documento

Postcondiciones: 1. El documentos será guardado con los cambios en el servidor

Flujo Normal: 1. El sistema guarda los cambios del documento en el servidor

Flujo Alternativo:

Excepciones: Si el usario no tiene permisos para guardar el documento, el sistema


muestra un mensaje de error y los cambios efectuados en el
documento no se almacenarán

Incluye:

Proyecto Fin de Carrera | 237


Prioridad:

Frecuencia de uso: Alta

Nombre: Imprimir Documento

Actor: Usuario

Descripción: El usuario imprime un documento

Iniciador: El usuario selecciona un documento y escoge la opción imprimir

Precondiciones: 1. El documento seleccionado no es una carpeta

Postcondiciones: 1. El documento se imprime

Flujo Normal: 1. El sistema muestra un dialogo de impresion


2. El usuario selecciona los parametros de impresion que desee
para el documento
3. El sistema imprime el documento

Flujo Alternativo: 2. El usuario cancela la impresion. Finaliza el caso de uso

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Baja

Proyecto Fin de Carrera | 238


Nombre: Subir Documento

Actor: Usuario

Descripción: El usuario sube un nuevo fichero al servidor

Iniciador: El usuario selecciona una carpeta y escoge la opcion Subir Documento

Precondiciones: 1. El usuario ha seleccionado una carpeta.


2. El usuario tiene permisos de escritura sobre la carpeta
seleccionada

Postcondiciones: 1. El documento subido será almacenado en el servidor

Flujo Normal: 1. El sistema muestra al usuario el dialgo de apertura de fichero


2. El usuario selecciona el fichero a subir
3. El sistema guarda el fichero seleccionado en el servidor y
distribuye el evento por la red.

Flujo Alternativo: 3. Si existe un fichero con el mismo nombre y ruta en el servidor, el


sistema da a elegir al usuario entre tres opciones: sobreescribir,
renombrar el nuevo fichero o cancelar
a. Se sobreescribe el fichero en el servidor y vamos al
paso 3.
b. Se le da un nuevo nombre al documento y volvemos al
paso 3.
c. Termina el caso de uso

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Baja

Proyecto Fin de Carrera | 239


Nombre Agregar Carpeta

Actor: Usuario

Descripción: El usuario crea una nueva carpeta en el servidor

Iniciador: El usuario selecciona una carpeta y escoge la opcion Agregar Carpeta

Precondiciones: 1. El usuario ha seleccionado una carpeta y no un documento.


2. El usuario tiene permisos de escritura sobre la carpeta
seleccionada

Postcondiciones: 1. La carpeta seleccionada

Flujo Normal: 1. El sistema solicita al usuario el nombre para la nueva carpeta


2. El usuario introduce el nombre
3. El sistema crea la carpeta el fichero seleccionado en el servidor
y distribuye el evento por la red.

Flujo Alternativo: 2. Si existe una carpeta con el mismo nombre y ruta en el servidor, el
sistema da a elegir al usuario entre dos opciones: renombrar el nuevo
fichero o cancelar
a. Se le da un nuevo nombre al documento y volvemos al
paso 3.
b. Termina el caso de uso

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Baja

Proyecto Fin de Carrera | 240


Nombre: Descargar Fichero

Actor: Usuario

Descripción: El usuario descarga un fichero del servidor

Iniciador: El usuario selecciona una carpeta y escoge la opcion Subir Documento

Precondiciones: 1. El usuario ha seleccionado un documento.


2. El usuario tiene permisos de lectura sobre el documento
seleccionada

Postcondiciones: 1. El documento se descargará en el equipo del usuario

Flujo Normal: 1. El sistema solicita al usuario la carpeta donde quiere guardar


localmente el documento
2. El usuario introduce la carpeta destino
3. El sistema guarda el fichero seleccionado en el equipo del
cliente en la carpeta seleccionada y distribuye el evento por la
red.

Flujo Alternativo: 3. Si existe un fichero con el mismo nombre y ruta en el servidor, el


sistema da a elegir al usuario entre tres opciones: sobreescribir,
renombrar el nuevo fichero o cancelar
a. Se sobreescribe el fichero en el equipo cliente y vamos
al paso 3.
b. Se le da un nuevo nombre al documento y volvemos al
paso 3.
c. Termina el caso de uso

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Baja

Proyecto Fin de Carrera | 241


Nombre: Eliminar Fichero

Actor: Usuario

Descripción: El usuario elimina un documento del servidor

Iniciador: El usuario selecciona un documento y escoge la opcion eliminar


documento

Precondiciones: 1. El usuario ha seleccionado un documento o carpeta.


2. El usuario tiene permisos de escritura sobre el documento
seleccionada

Postcondiciones: 1. El documento a eliminar será borrado en el servidor

Flujo Normal: 1. El sistema elimina el fichero seleccionado del servidor y


distribuye el evento por la red.

Flujo Alternativo:

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Baja

Proyecto Fin de Carrera | 242


Nombre: Mover Documento

Actor: Usuario

Descripción: El usuario mueve un documento de una carpeta a otra

Iniciador: El usuario selecciona un documento

Precondiciones: 1. El usuario ha seleccionado una carpeta.


2. El usuario tiene permisos de escritura sobre el documento
seleccionada

Postcondiciones: 1. El usuario escoge la carpeta destino


2. El sistema mueve el documento seleccionado a la carpeta
destino y distribuye el evento por la red.

Flujo Normal: 2. Si el usuario no tiene permisos de escritura el la carpeta destino el se


cancela el traslado del documento

Flujo Alternativo:

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Media

Nombre: Ver Propiedades Documento

Actor: Usuario

Proyecto Fin de Carrera | 243


Descripción: El usuario accede a las propiedades del fichero

Iniciador: El usuario selecciona un documento y escoge la opcion ver


propiedades documento

Precondiciones: 1. El usuario ha seleccionado una carpeta.

Postcondiciones: 1. Los cambios realizados en las propiedades en los documentos


se verán reflejados en el servidor

Flujo Normal: 1. El sistema muestra al usuario las propiedades del fichero


2. Mientras el usuario lo desee
a. Cambia el nombre del documento
b. Cambia los permisos del documento
3. El usuario selecciona guardar los cambios y salir de las
propiedades del documento
4. El sistema almacena los cambios y distribuye el evento por la
red.

Flujo Alternativo: 3. El usuario selecciona salir sin guardar los cambios. El caso de uso
termina

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Media

Nombre: Chatear

Proyecto Fin de Carrera | 244


Actor: Usuario

Descripción: El usuario accede al chat

Iniciador: El usuario accede al chat

Precondiciones: -

Postcondiciones: -

Flujo Normal: 1. El sistema muestra al usuario la ventana de chat


2. Mientras el usuario mantega el chat abierto
a. El usuario escribe lo que desee decir
b. El sistema muestra en la ventana de chat lo que el
usuario (y/o otros usuarios) hayan escrito.

Flujo Alternativo: -

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Alta

Nombre: Establecer Conversación Privada

Actor: Emisor, Receptor

Descripción: El usuario conversa de forma privada con otro usuario.

Proyecto Fin de Carrera | 245


Iniciador: El usuario selecciona un usuario (en adelante el receptor) y escoge la
opcion ver propiedades documento.

Precondiciones: 1. El receptor seleccionado no es el propio usuario.

Postcondiciones: -

Flujo Normal: 1. El sistema avisa el receptor de que el usuario desea iniciar una
conversación privada.
2. El receptor acepta.
3. Mientras el usuario y el receptor mantengan abierta la
conversación:
a. El usuario escribe un texto para enviar al receptor.
b. El sistema envia el texto al receptor.

Flujo Alternativo: 2. El receptor rechaza iniciar la nueva conversación. El caso de uso


termina.

Excepciones:

Incluye:

Prioridad:

Frecuencia de uso: Alta

Nombre: Iniciar Videoconferencia

Actor: Usuario

Descripción: El usuario realiza una videoconferencia de forma privada con otro


usuario.

Proyecto Fin de Carrera | 246


Iniciador: El usuario selecciona un usuario (en adelante el receptor) y escoge la
opcion ver iniciar videoconferencia

Precondiciones: 1. El receptor seleccionado no es el propio usuario.

Postcondiciones: -

Flujo Normal: 1. El sistema avisa el receptor de que el usuario desea iniciar una
conversación privada.
2. El receptor acepta.
3. El sistema captura el audio y video del usuario y del receptor y
lo envía al receptor y al usuario.

Flujo Alternativo: 2. El receptor rechaza iniciar la nueva videoconferencia. El caso de uso


termina.

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Baja

Nombre: Cambiar Rol

Actor: Usuario

Descripción: El usuario cambia su rol actual

Iniciador: El usario selecciona la opcion cambiar rol

Precondiciones: -

Proyecto Fin de Carrera | 247


Postcondiciones: 1. Los cambio de rol será notificado a todos los usuarios
conectados

Flujo Normal: 1. El sistema muestra al usuario la lista con todos sus posible
roles
2. El usuario escoge uno de los roles de la lista
3. El sistema actualiza el rol actual del usuario

Flujo Alternativo: -

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Baja

Nombre: Gestionar Plugins

Actor: Usuario

Descripción: El usuario accede a los datos de todos los plugins instalados

Iniciador: El usuario selecciona un documento y escoge la opcion ver


propiedades documento

Precondiciones: -

Postcondiciones: 1. Los cambios realizados en los plugins son almacenado

Flujo Normal: 1. El sistema muestra al usuario todos los plugins instalados

Proyecto Fin de Carrera | 248


2. Mientras el usuario no cierre la ventana
a. El usuario selecciona un plugin
b. Si el usuario desea cambiar la visibilidad de un plugin
se inicia el caso de uso Cambiar Visibilidad.
c. Si el usuario desea agregar un nuevo plugin se inicia el
caso de uso Agregar Plugin.
d. Si el usuario desea eliminar un plugin se inicia el caso
de uso Eliminar Plugin.

Flujo Alternativo: -

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Media

Nombre: Cambiar Visibilidad

Actor: Usuario

Descripción: El usuario cambia la visibilidad de un plugin

Iniciador: El usuario selecciona un plugin y escoge la opcion cambiar visibilidad.

Precondiciones: 1. Esta ejecutandose el caso de uso Gestionar Pluigns

Postcondiciones: 1. Los cambios realizados en los plugins seran permanentes

Flujo Normal: 1. El usuario selecciona si desea que el plugin sea visible o


invisible.
2. El sistema actualiza la visibilidad del plugin.

Proyecto Fin de Carrera | 249


Flujo Alternativo: -

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Baja

Nombre: Agregar Plugin

Actor: Usuario

Descripción: El usuario agrega un nuevo plugin a la aplicacion

Iniciador: El usuario selecciona un plugin y escoge la opcion agregar plugin

Precondiciones: 1. Esta ejecutandose el caso de uso Gestionar Pluigns

Postcondiciones: 1. Los cambios realizados en los plugins seran permanentes

Flujo Normal: 1. El sistema pregunta al usuario por la ruta hacia el nuevo plugin
en el sistema de archivos local.
2. El usuario introduce la ruta del archivo del nuevo plugin.
3. El sistema copia el nuevo plugin y lo carga.

Flujo Alternativo: 3. El sistema detecta que el archivo proporcionado por el usuario no es


un plugin válido. El sistema muetra un aviso al usuario y se acaba el
caso de uso.

Excepciones: -

Incluye: -

Proyecto Fin de Carrera | 250


Prioridad: -

Frecuencia de uso: Baja

Nombre: Eliminar Plugin

Actor: Usuario

Descripción: El usuario elimina uno de los plugins instalados en la aplicación

Iniciador: El usuario selecciona un plugin y escoge la opcion eliminar plugin

Precondiciones: 1. Esta ejecutandose el caso de uso Gestionar Pluigns

Postcondiciones: 1. Los cambios realizados en los plugins seran permanentes

Flujo Normal: 1. El sistema elimina el plugin

Flujo Alternativo: -

Excepciones: -

Incluye: -

Prioridad: -

Frecuencia de uso: Baja

Tabla 10.1: Especificación detallada de los casos de uso

Proyecto Fin de Carrera | 251


B. Histórico del diseño de la interfaz gráfica de usuario

A continuación se expone el histórico de versiones del diseño de la interfaz de usuario de


la ventana principal de la aplicación cliente.

Primera Versión

Inspirados en los SOs Web, tales como podría ser EyeOS, la primera propuesta de
interfaz fue similar a la siguiente:

Ilustración 112: Captura de pantalla de EyeOS, que


ilustraría la idea básica del primer diseño de la GUI

Seguidamente, podemos observar el diseño de interfaz propuesto, basándonos en el ya


citado EyeOS. Las partes que podemos distinguir son:
• Lanzador de aplicaciones: contiene los iconos de las mini-aplicaciones instaladas
en el sistema. Nos permite ejecutarlas con un sólo click.
• Escritorio: Similar al escritorio de las interfaces de usuario de la mayor parte de los
SO actuales. Permite agregar iconos: ya sea para hacer referencia a aplicaciones
como a documentos.
• Navegador de ficheros: aplicación clave del diseño, permite acceder al sistema de
archivos compartidos. Desempeñaría tareas similares a las de Explorer en

Proyecto Fin de Carrera | 252


Windows, Nautilus en Gnome o Finder en Mac OS X.

Ilustración 113: Primer prototipo de la interfaz

El objetivo perseguido con este diseño era el de construir una interfaz que hiciese creer al
usuario que se encuentra utilizando un sistema operativo completo.

Razones del rechazo:


• Demasiadas ventanas al mismo tiempo
• Dificultad en la localización de las aplicaciones
• Documentos poco visibles
• Interfaz disperso
• Difícil de aprender para un usuario poco experimentado.
• Excesiva complejidad a la hora de la implementación.

Segunda versión

La ventana se divide en tres secciones:


• Norte. En ella se encuentra la barra de herramientas que permite el acceso a las
distintas funcionalidades del sistema.
• Oeste. Se divide a su vez en dos zonas:
• Superior: Permite acceder a las mini-aplicaciones del sistema. Para
ejecutarlas sólo habrá que realizar doble click.

Proyecto Fin de Carrera | 253


• Inferior: muestra un árbol con los usuarios que se encuentran conectados
clasificados por su rol. Incorpora también una barra de herramientas que
permite realizar las tareas más comunes.
• Centro. Panel donde se visualizará en contenido de las aplicaciones instaladas en
el sistema. La lista desplegable que figura en la barra de herramientas asociada al
panel de la aplicación permite enviar el documento que está siendo actualmente
editado a otra aplicación.

Ilustración 114: Diseño de la interfaz de ventana


principal de la aplicación (versión 2)

Motivos del rechazo:


• Modelo demasiado orientado a las aplicaciones.
• No existe una forma sencilla de acceder a los documentos almacenados en el
servidor.
• Funcionalidad básica de los programas demasiado oculta.
• No permite ejecutar varias mini-aplicaciones de forma simultánea.
• Poca utilidad de la barra de herramientas de la aplicación.

Proyecto Fin de Carrera | 254


Tercera Versión

En esta tercer versión, evolución de la segunda (anteriormente presentada) por fin


aparece el componente en torno al que girará el resto del interfaz: El árbol de documentos
compartidos.

En las siguientes figuras podemos ver el diseño correspondiente y su revisión:

Ilustración 115: Tercer prototipo de la Ilustración 116: Tercer prototipo de la


interfaz interfaz revisado

Proyecto Fin de Carrera | 255


C. Manual de operación

Instalación del sistema

Requisitos previos

Se requerirá un SO operativo que soporte la versión de Java 1.5. Ésta versión de Java se
podrá instalar gracias al soporte físico adjunto. Se aportan instaladores para Windows y
Linux (Mac OS X lo tienen preinstalado de serie).

Para los servidores se requiere tener una conexión con un servidor MySQL. Se aportan
instaladores para Windows, Linux y Mac OS X de ésta aplicación.

Los ordenadores donde se instalen las aplicaciones deben tener soporte para conexión en
red y estar conectados permanentemente.

Instalación de las aplicaciones

Para la instalación de la aplicación cliente y de los servidores dispondremos de


instaladores para Windows y Mac OS X. Para el resto de plataformas se proveerán los
ficheros .jar, junto con un script de Shell para su ejecución.

• Windows. El instalador de Windows para el cliente se llamará “setupCliente.exe”,


para el servidor de metainformación de las aplicaciones tendremos otro que se
llamará “setupMI_App.exe” y para el servidor de metainformación de los
documentos tendremos, por último, uno llamado “setupMI_fich.exe”. Los tres
instaladores crearán una carpeta donde especifiquemos durante el asistente de
instalación. Éste asistente es autoexplicativo. Tras la instalación, dispondremos de
una entrada en el menú inicio que se llamará “Cliente”, “Metainformación
Aplicaciones” ó “Metainformación Ficheros”, según la aplicación instalada. Cuando
instalemos un servidor en cualquier sistema, también se nos agregará una entrada

Proyecto Fin de Carrera | 256


en el menú inicio que nos permitirá iniciar los servicios necesarios para el correcto
funcionamiento de JavaSpaces.

• Mac OS X. Para Mac OS X se aporta un fichero DMG donde se contienen


ejecutables para el cliente y los servidores. Deberemos de arrastrar y soltar las
carpetas que se correspondan con lo que queremos mantener en nuestro sistema
(el cliente, algún servidor, todo el conjunto, etc.) a la carpeta “Aplicaciones” del
sistema. Si abrimos cualquiera de éstas carpetas, podremos ver los ejecutables
correspondientes. Cada carpeta asociada a un servidor tendrá una subcarpeta
llamada “servicios”. Dentro de ésta carpeta tendremos un script de AppleScript que
nos permitirá iniciar los servicios necesarios para el correcto funcionamiento de
JavaSpaces.

• Linux y otros sistemas operativos. Para el resto de sistemas, simplemente


arrastraremos las carpetas que se proveen a cualquier carpeta del disco duro.
Dentro de cada carpeta tendremos un script de Shell que nos permitirá iniciar cada
ejecutable. En las carpetas asociadas a los servidores, en una subcarpeta llamada
“servicios” dispondremos de un script de Shell que nos permitirá iniciar los servicios
para el correcto funcionamiento de JavaSpaces.

Configuración del sistema

Creación de la base de datos

Se aportan scripts específicos para la creación y relleno con datos de prueba para la base
de datos necesaria para el funcionamiento del sistema.

Los scripts aportados realizan las siguientes operaciones:

• crearBD. Crea la base de datos necesaria para el sistema. Además, crea un


usuario con nombre “admin” y contraseña “admin”.
• rellenarBD. Crea las tablas de la BD y las rellena con datos de prueba. Conviene

Proyecto Fin de Carrera | 257


modificar el fichero “bdMetainformacion.sql” adjunto para reflejar en la base de
datos la información deseada en nuestro sistema (usuarios y claves, roles, etc.).
• BDBackup. Realiza una copia de seguridad de la base de datos del sistema.

Configuración de los servidores

Los servidores tienen adjunto un fichero de configuración. Éste fichero se llama “config” y
es de texto, es decir, se puede abrir con cualquier editor de texto plano. Contiene dos
filas:

La primera fila (“datos”) deberá tener a continuación el path absoluto de la carpeta donde
guardaremos físicamente los documentos del sistema.

La segunda fila (“MIBD”) tiene tres elementos: La dirección IP del ordenador donde se
encuentra la base de datos del sistema instalada, el nombre de usuario para la base de
datos y la contraseña para ese usuario.

Todos éstos parámetros deberemos modificarlos adecuadamente.

Ejecución del sistema

El orden de ejecución de las aplicaciones es el siguiente:

$ Ejecutar el script que inicia los servicios de JavaSpaces.


$ Ejecutar los servidores (en cualquier orden)
$ Ejecutar los clientes.

Según el sistema operativo, dispondremos de éstos elementos en un lugar u otro de


nuestro ordenador. Consultar la sección de instalación.

Proyecto Fin de Carrera | 258


D. Manual de usuario

VENTANA PRINCIPAL

Al abrir la aplicación nos encontramos con la siguiente ventana:

Ilustración 117: Pantalla principal de la aplicación

Como se puede observar la ventana se divide en tres zonas:

• Lista de aplicaciones.
• Árbol de usuarios conectados.
• Árbol de documentos compartidos.

Documentos

En el panel central podemos observar los documentos a los que se tiene acceso en, como
mínimo, modo lectura. Para una fácil organización, los documentos aparecen organizados
en forma de árbol, de manera similar a como se estructuran los sistemas de archivos

Proyecto Fin de Carrera | 259


típicos.

Las acciones disponibles para un documento (o directorio) se encuentran en la barra de


herramientas del árbol de documentos son las siguientes:

• Abrir el documento para su anotación


• Reenviar un mensaje
• Imprimir un documento
• Guardar una copia local de un documento.
• Subir un nuevo documento.
• Crear una carpeta.
• Eliminar un documento o carpeta.
• Consultar los atributos de un documento o directorio

Aplicaciones

Se muestran las aplicaciones disponibles. Para ejecutar alguna de ellas bastará con hacer
doble click sobre su nombre.

Usuarios

Se muestra un árbol con los usuarios conectados en un momento dado, clasificados por
rol. El árbol lleva asociada una barra de herramientas en su parte inferior que nos permite:

• Editar la metainformación del sistema:


• Cambiar el rol actual.
• Iniciar una conversación con el usuario seleccionado en el árbol.
• Enviar mensaje al usuario seleccionado en el árbol.
• Iniciar una videoconferencia con el usuario seleccionado en el árbol.

Proyecto Fin de Carrera | 260


Editor

El editor está formado por tres elementos gráficos:

! Barra de controles de dibujo. Desde esta barra podemos incluir anotaciones,


eliminarlas, guardar el documento, etc.

! Lienzo. Panel donde se visualiza el documento y sus anotaciones.

! Barra de estado. Barra que controla la navegación del documento, permitiéndonos


desplazarnos por la páginas de éste.

Proyecto Fin de Carrera | 261


E. Dificultades encontradas

A lo largo del desarrollo del proyecto se han encontrado dificultades de diversa índole. A
continuación se detallan las de mayor relevancia. Hay que destacar que la simplicidad de
uso de la aplicación cliente final entra en contraste con gran dificultad en la resulución de
la mayoría de dificultades encontradas, debido sobre todo al uso de tecnologías
complejas, y a menudo, muy diferentes entre sí.

1. Envío de eventos de registro de plug-ins para el sistema de versionado. El


sistema de plug-ins tiene un sistema de versionado que permite la descarga directa
de nuevas versiones de un plug-in concreto desde otros clientes. Para que el envío
de los eventos necesarios fuese posible se encontró la dificultad de que un plug-in
no era un componente. Tras un arduo proceso de diseño, se convirtió la
abstracción que permite la implementación de plug-ins en un componente gráfico
de la plataforma. Gracias a ésto, la transmisión de eventos es posible. A pesar de
adoptar ésta solución, en un futuro, se deberá crear un sistema de registro
dinámico de componentes gráficos en el sistema, de tal forma que cada plug-in, al
ser cargado de manera dinámica, registre los componentes que lo componen en la
metainformación del sistema. Así mismo, una vez que el plug-in deje de estar
disponible, los componentes deberán des-registrarse. Ésto se podría conseguir
mediante un servidor de aplicaciones.

2. Los fallos en el DConector implicaban dificultades en las posteriores


ejecuciones de la aplicación cliente. El DConector es el encargado de
comunicarse con JavaSpaces. Si ésta abstracción falla en algún momento, puede
ocurrir que el token de sincronización se pierda. Para evitar ésto, ante cualquier
excepción posible que implique el fin del funcionamiento de DConector, el token se
escribirá en JavaSpaces, de tal forma, que al iniciar una nueva ejecución de
DConector (por ejemplo, mediante la ejecución de la aplicación cliente), el token se
encuentre disponible.

Proyecto Fin de Carrera | 262


3. El sistema de almacenamiento persistente de la metainformación del sistema
era un fichero de texto plano. El uso de un fichero de texto plano tenía diversos
inconvenientes: Problemas de seguridad, ineficiencia en la recuperación de datos,
incapacidad de recuperación ante la corrupción del fichero, etc. Por ello, se migró a
una base de datos para almacenar la metainformación del sistema. El sistema de
gestión de base de datos escogido fue MySQL, ya que es gratuito. Se crearon
abstracciones para el acceso a la BD que permitieran que un futuro, si se deseaba,
se cambiase éste sistema de almacenamiento por otro sin necesidad de cambiar la
implementación del resto del sistema.

4. Visualización incorrecta de caracteres en la aplicación final en ciertas


plataformas. Se ha realizado una recodificación de todo el código fuente para que
sea UTF-8. Así aseguramos que la visualización será siempre correcta en cualquier
SO. Además, si se internacionalizase el código, no habría problemas en la
codificación de otros caracteres “extraños”.

5. La transmisión de datos de gran tamaño a través de JavaSpaces era inviable.


Puesto que JavaSpaces no es adecuado para la transmisión de datos de gran
tamaño, se han implementado abstracciones sobre los mecanismos de transmisión
mas utilizados: Sockets y RMI. Mediante éstas abstracciones, se podrán transmitir
bytes entre usuarios sin necesidad de usar JavaSpaces. Para la transmisión de
información de gran tamaño, como pueden ser imágenes o ficheros (cuando
subimos nuevos ficheros al entorno compartido de trabajo), se usan éstas
abstracciones.

6. Captura y transmisión de vídeo. Para la captura y transmisión de vídeo para la


videoconferencia, se han encontrado dos dificultades fundamentales: Como
capturar éste vídeo y como transmitirlo de forma óptima. Para la transmisión, se
han usado las abstracciones comentadas en el punto anterior. Para la captura, se
ha hecho uso de bibliotecas de software libre que permiten el acceso al hardware.
A pesar el uso de éstas bibliotecas, la implementación ha sido bastante compleja,

Proyecto Fin de Carrera | 263


requiriéndose un gran esfuerzo para comprender el sistema de acceso a hardware
utilizado. Las bibliotecas usadas tienen un inconveniente, además, y es el hecho de
que solo capturan a 7 fps en SO's distintos a Windows (en éste es a 20 fps). Éste
hecho ha implicado la necesidad de que las transmisiones sean lo más óptimas
posibles, para evitar que la cantidad de fps descienda aún más. Finalmente se ha
conseguido una media en SO's distintos a Windows de 6 fps. En Windows se ha
pasado a 18 fps.

7. Captura de audio. La captura de audio en Java es altamente compleja debido a


los amplios conocimientos que se deben tener acerca de como se modela el
sistema de audio en un computador. Se deben entender abstracciones tales como
mezclador, línea de datos, flujo de audio, etc. Ésto ha requerido un gran esfuerzo
en búsqueda y estudio de bibliografía acerca de éste tema.

8. Transmisión de audio. En la transmisión de audio se han encontrado muchas


dificultades. Al contrario que en el vídeo, si una parte del audio no se transmite o se
transmite desordenadamente, las frases que se estarán recibiendo no tendrán
ningún sentido (en el vídeo, la pérdida de una imagen no tiene demasiada
importancia, ya que en un pequeño intervalo de tiempo recibiremos una nueva muy
parecida a la anterior). Se ha tenido que implementar un sistema de buffers para el
envío y recepción de tramas de audio. A éstas tramas, se les aplican mecanismos
de control de errores que permiten detectar cuando una trama es incorrecta, para
que se retransmita. Además, se realiza un control de flujo para evitar que haya
desbordamiento de los buffers. Por último, se detecta el órden de emisión de cada
trama, para que, en caso de ser necesario, se reordenen en el receptor
adecuadamente. Para conseguir los puntos anteriores, se ha realizado una
implementación de un protocolo handshake y una implementación básica del
protocolo TCP. Además, todas las transmisiones se realizan mediante sockets,
para mejorar la eficiencia.

9. Cuando un usuario cambiaba de rol, el árbol de documentos no se


actualizaba correctamente. Al cambiar de rol, es posible que un usuario tenga

Proyecto Fin de Carrera | 264


acceso a nuevos documentos y deje de tener acceso a otros. Ésto debe reflejarse
de forma gráfica en el árbol de documentos de la aplicación cliente. Para solucionar
ésto, se ha debido sobrecargar el método “procesarMetainformacion” del
componente DIArbolDocumentos, de tal forma que cuando se detecte un cambio
de rol, se realice una actualización correcta del árbol.

10. Problemas de eficiencia en la videoconferencia. La reproducción de audio y


vídeo conjuntamente tiene un gran impacto en el sistema, debido a que es muy
ineficiente. Se deberá buscar en un futuro mecanismos de reproducción de
contenidos multimedia que tengan una mayor eficiencia. Ahora mismo, la solución
adoptada es la compresión desde el emisor en formato JPEG de la imagen
transmitida, y en el receptor, evitar cargar varias veces la misma imagen, es decir,
esperar a que llegue una nueva imagen antes de seguir reproduciendo.

11. El cambio en los permisos de acceso a un documento debía verse reflejado


de forma gráfica en la anotación colaborativa. Para conseguir ésto, ante la
recepción de un evento de cambio de permisos sobre un documento sobre el que
se está anotando se actuará del siguiente modo: Si dejamos tener permisos de
escritura sobre él, se desactivará el botón de guardado del sistema de anotación, y
si dejamos de tener permisos de lectura, se dará un aviso y se cerrará el sistema
de anotación (evidentemente, en cualquier caso, el resto de la aplicación seguirá
funcionando sin problemas).

12. El sistema de inicialización de servicios de JavaSpaces pasó a ser comercial,


y posteriormente se descontinuó su desarrollo. Se ha empleado un gran
esfuerzo en la implementación de scripts que permitan iniciar los servicios
necesarios para JavaSpaces. Gracias a éstos scripts, se evita la utilización se
software de terceros, se asegura la disponibilidad del código fuente de éstos (son
scripts no compilados), y se facilita la inicialización de los servicios, gracias a que
tan solo deberemos iniciar un script para iniciar todos los servicios que sean
necesarios (en el software de terceros nos encontraremos a menudo con gran
cantidad de servicios que no tendrán utilidad en éste sistema).

Proyecto Fin de Carrera | 265


13. La instalación y ejecución de la aplicación cliente y los servidores resultaba
bastante compleja. Para solucionar ésto, se han creado una serie de scripts
“amigables” para los diversos SO's que permiten la instalación y ejecución de la
aplicación y los servidores. En Windows, incluso, se crean entradas en el menú
inicio. En MacOSX, se dan ejecutables especialmente creados para éste sistema.

14. Los componentes gráficos reutilizables implementados tenían un difícil uso.


Los componentes gráficos reutilizables requerían la programación a mano de todo,
puesto que no se podían usar con aplicaciones de diseño gráfico de GUI's. Para
conseguir ésto, se han reimplementado siguiendo el modelo definido por
JavaBeans. Actualmente, por ejemplo, en Netbeans, funcionan con tan solo
arrastrar y soltar los componentes sobre cualquier panel o ventana.

15. Si un usuario habría un documento para anotar sobre él y éste estaba siendo
anotado por otro usuario que no había guardado los cambios, debía
transmitirse información acerca de las anotaciones producidas. Para realizar
ésto último se ideó un sistema de tokens. Si un usuario posee un token, entonces
puede anotar y tiene las últimas anotaciones realizadas sobre un documento.
Cuando un nuevo usuario desee anotar sobre éste documento, se detecta quién
tiene el token y se realiza una transmisión (mediante RMI) desde éste último de
toda la información del sistema de anotaciones (las anotaciones realizadas, quién
las realizó, las pilas para deshacer o rehacer acciones, etc.). Si el token no existe,
entonces nadie está editando el documento y se recupera directamente desde el
servidor de ficheros, el cuál mantiene persistentemente los ficheros del espacio de
trabajo compartido.

16. La interfaz gráfica resultaba compleja para la mayoría de usuarios. En la


sección dedicada al histórico de la realización de la interfaz gráfica se puede
observar el refinamiento realizado. Se han realizado pequeñas encuestas a
usuarios con distintos niveles de conocimientos en informática para observar las
dificultades que encontraban a la hora de acceder a la funcionalidad del sistema

Proyecto Fin de Carrera | 266


completo. Tras sucesivas versiones se llegó a una interfaz bastante ágil, simple y
con acceso a todos los elementos principales de un simple golpe de vista. Todos
los usuarios encuestados estuvieron de acuerdo en que ésta última interfaz gráfica
implementada era la más acertada para ellos.

Proyecto Fin de Carrera | 267


F. Pruebas de Rendimiento

Se van a realizar una serie de pruebas para ver el consumo de recursos cuando está
funcionando el sistema implementado. En éstas se va a ejecutar la aplicación cliente y los
servicios necesarios para el correcto funcionamiento del sistema en un PC.

El PC donde se realizarán las pruebas tienen las siguientes características:


" Core 2 Duo
" 1 GB RAM
" HD SATA 80GB
" LAN Wifi
" S.O. Mac OS X

Para la obtención de los datos se han utilizado las aplicaciones Monitor de Actividad
(monitorización del consumo de memoria) y BigTop ( uso de CPU y tráfico de red).

Consumo de memoria

El primer paso será arrancar los servicios necesarios para la ejecución (JavaSpaces,
Transaction Manager). Con estos servicios arrancados se consumen unos 22 MB de
memoria RAM. Como podemos ver en la captura siguiente:

Ilustración 118: Consumo de memoria al lanzar los servicios (JavaSpace y


Transaction Manager)
Posteriormente arrancamos el servidor de Ficheros, apreciándose un incremento de la
memoria usada de unos 34MB:

Proyecto Fin de Carrera | 268


Ilustración 119: Consumo de memoria tras lanzar el servidor de ficheros

A continuación, se arranca el servidor de Metainformación, produciéndose un incremento


del consumo de memoria de unos 21MB

Ilustración 120: Consumo de memoria tras lanzar el servidor de


metainformación

Finalmente se arranca la aplicación cliente, incrementándose el consumo de memoria en


unos 42MB.

Ilustración 121: Comsumo de memoria tras lanzar una aplicación cliente

Abrimos un documento pesado (un pdf de muchas páginas). El consumo se incrementa


en casi 100MBs.

Ilustración 122: Consumo de memoria tras la apertura de un documento

Proyecto Fin de Carrera | 269


Sumando todos los consumos de memoria, tenemos que todo el sistema servidor
ocuparía unos 77MB (sin incluir el sistema de gestión de bases de datos). Para el cliente,
el consumo de memoria oscilaría entre los 42MB y los 150 MB con un documento abierto.

Uso de CPU

El consumo de ciclos de procesador, tanto de las aplicaciones cliente como de los


servidores es escaso, no incrementándose en demasía salvo en casos puntuales (sobre
todo en el caso del cliente).

En la siguiente imagen podemos ver el uso de CPU durante la edición de un documento,


los picos corresponde a los casos de uso intensivo de las anotaciones a mano alzada:

Ilustración 123: Uso de la CPU durante la anotación de un documento

Uso de red
El consumo de red red bajo (salvo en los casos en los que se intercambian documentos,
en cuyo caso el consumo experimenta un pico).

En la siguiente gráfica podemos observar el tráfico generado al iniciar una aplicación


cliente:

Proyecto Fin de Carrera | 270


Ilustración 124: Uso de la red en el arranque de una aplicación cliente

El primero de los picos corresponde a la localización del JavaSpace y del manejador de


transacciones; el segundo pico es el producido por la comunicación entre el cliente y los
servidores. También cuando se abre un documento se produce un incremento del
consumo de red, tal y como se puede observar en la gráfica inferior:

Ilustración 125: Uso de la red durante la carga de un documento

Como podemos ver, incluso en los picos de tráfico de red, el uso de la red no pasa de los
3 KB.

Con los resultados obtenidos vemos que la plataforma que hemos usado así como la
implementación realizada es bastante eficiente, cumpliéndose así uno de los requisitos
iniciales.

Proyecto Fin de Carrera | 271


G. Bibliografía

1. Computer-Supported Cooperative Work: Its History and Participation. Grudin,


J. (1994). Computer 27 (4): 19–26. http://dx.doi.org/10.1109/2.291294

2. Readings in human-computer interaction: toward the year 2000. Baecker,


R.M.; Others, (1995). Morgan Kaufmann Publishers.

3. AMENITIES: una metodología para el desarrollo de sistemas cooperativos basada


en modelos de comportamiento y tarea. Garrido, J.L. Tesis Doctoral. Universidad
de Granada, 2003

4. Diseño de interfaces de usuario para aplicaciones colaborativas a partir de


modelos independientes de la computación. Rodríguez, M.L; J.L. Garrido; M.
Noguera; M.V. Hurtado; J.R. Polo.

5. Página principal del proyecto Habanero:


http://www.isrl.uiuc.edu/isaac/Habanero/

6. TOP: Una plataforma para el Desarrollo de Interfaces y Aplicaciones


Colaborativas sobre Web. Luis A. Guerrero, Roberto C. Portugal, David A. Fuller.

7. Creating a GUI with JFC/Swing. Sun Microsystems.


http://java.sun.com/docs/books/tutorial/uiswing/

8. Java Look and Feel Design Guidelines:


http://java.sun.com/products/jlf/ed1/dg/higix.htm

9. Introducción a Remote Method Invocation. Ramiro Lago (Febrero 2006).


http://www.proactiva-calidad.com/java/rmi/introduccion.html

Proyecto Fin de Carrera | 272


10. RMI Guide and Specifications. Sun Microsystems. Tabla de contenidos:
http://java.sun.com/j2se/1.3/docs/guide/rmi/spec/rmiTOC.html. Descripción del Protocolo
de Transporte para RMI: http://java.sun.com/j2se/1.3/docs/guide/rmi/spec/rmi-
protocol3.html.

11. JavaSpaces. Principles, Patterns and Practice. Eric Freeman, Susanne Hupfer,
Ken Arnold. Addison-Wesley.

12. Programación concurrente en Java. Principios y patrones de diseño. Doug


Lea. Addison-Wesley.

13. Jan Newmarch's Guide to Jini Technologie. Jan Newmarch. 2006.


http://jan.newmarch.name/java/jini/tutorial/Jini.xml

14. Jini Technology Starter Kit API Documentation. Sun Microsystems.


htttp://java.sun.com/producs/jini/2.1/doc/api/

15. Manual de referencia para MySQL 5.0. MySQL AB.


http://dev.mysql.com/doc/refman/5.0/es/index.html

16. Documentación de la librería PDFRenderer. Sun Microsystems.


http://dev.mysql.com/doc/refman/5.0/es/index.html

17. Getting Started with LTI-CIVIL. LTI Inc. http://lti-civil.org/gettingstarted.php

18. Proyecto fin de carrera: Diseño e implementación de una plataforma para el


desarrollo de sistemas groupware. Juan Antonio Ibáñez Santórum. Lenguajes y
Sistemas Informáticos. Universidad de Granada. 2004

Proyecto Fin de Carrera | 273

También podría gustarte