Servicio de interfaces gr´aficas para entornos …lsub.org/ls/export/pfc_wdgd.pdfentornos...

70
Servicio de interfaces gr´ aficas para entornos distribuidos Sergio de Mingo Gil 22 de junio de 2004

Transcript of Servicio de interfaces gr´aficas para entornos …lsub.org/ls/export/pfc_wdgd.pdfentornos...

Servicio de interfaces graficas para entornos

distribuidos

Sergio de Mingo Gil

22 de junio de 2004

Indice general

1. Introduccion 4

1.1. Sistemas distribuidos . . . . . . . . . . . . . . . . . . . . . . . 5

1.2. Interfaz de usuario . . . . . . . . . . . . . . . . . . . . . . . . 6

1.3. Uso distribuido de las interfaces graficas de usuario . . . . . . 7

1.4. Plan B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

1.4.1. Protocolo Bp . . . . . . . . . . . . . . . . . . . . . . . 10

1.5. Java y AWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2. Objetivos 13

2.1. Descripcion del problema . . . . . . . . . . . . . . . . . . . . . 14

2.2. Objetivos a cumplir . . . . . . . . . . . . . . . . . . . . . . . . 15

3. Metodologıa y Requisitos 17

3.1. El modelo en espiral . . . . . . . . . . . . . . . . . . . . . . . 17

3.2. Requisitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4. Arquitectura y diseno 22

4.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.2. Prototipo 1: Servidor de widgets . . . . . . . . . . . . . . . . . 24

4.2.1. Diseno del protocolo STRp . . . . . . . . . . . . . . . . 24

4.2.2. Diseno del widget . . . . . . . . . . . . . . . . . . . . . 25

4.2.3. Almacenando widgets . . . . . . . . . . . . . . . . . . . 27

4.3. Prototipo 2: Servidor de widgets y eventos . . . . . . . . . . . 28

4.3.1. Proceso de gestion de eventos . . . . . . . . . . . . . . 28

4.4. Prototipo 3: Servidor de widgets y eventos sobre Bp . . . . . . 31

4.4.1. Diseno del protocolo Bp . . . . . . . . . . . . . . . . . 31

4.4.2. Cajas de proposito especifico: /mouse, /keyboard y

/clipboard . . . . . . . . . . . . . . . . . . . . . . . . . 33

1

INDICE GENERAL 2

5. Implementacion 36

5.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5.2. Prototipo 1: Servidor de widgets . . . . . . . . . . . . . . . . . 36

5.2.1. La Caja . . . . . . . . . . . . . . . . . . . . . . . . . . 38

5.2.2. El sistema de cajas . . . . . . . . . . . . . . . . . . . . 43

5.3. Prototipo 2: Servidor de widgets y eventos . . . . . . . . . . . 44

5.3.1. Los escuchadores . . . . . . . . . . . . . . . . . . . . . 45

5.3.2. Notificacion y recoleccion de eventos . . . . . . . . . . 45

5.3.3. La caja /events . . . . . . . . . . . . . . . . . . . . . . 47

5.4. Prototipo 3: Servidor de widgets y eventos sobre Bp . . . . . . 48

5.4.1. Implementacion del protocolo Bp . . . . . . . . . . . . 48

5.4.2. Implementacion de la conexion . . . . . . . . . . . . . 50

5.4.3. Implementacion de /keyboard y /mouse . . . . . . . . 53

5.4.4. Implementacion de /clipboard . . . . . . . . . . . . . . 54

6. Validacion y pruebas 55

6.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

6.2. Prototipo 1: Servidor de widgets . . . . . . . . . . . . . . . . . 55

6.3. Prototipo 2: Servidor de widgets y eventos . . . . . . . . . . . 58

6.4. Prototipo 3: Servidor de widgets y eventos sobre Bp . . . . . . 60

7. Conclusiones 65

7.1. Objetivos cumplidos . . . . . . . . . . . . . . . . . . . . . . . 65

7.2. Lecciones aprendidas . . . . . . . . . . . . . . . . . . . . . . . 66

7.3. Valoracion personal . . . . . . . . . . . . . . . . . . . . . . . . 67

7.4. Trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Bibliografıa 69

RESUMEN 3

Resumen

El objetivo de este proyecto es la implementacion de un servicio que

ofrezca un mecanismo simple para el manejo remoto de interfaces graficos de

usuario. Con este servicio se pretende exportar toda la funcionalidad de las

cajas [3], abstraccion basica del sistema de ficheros de plan B[4], para el mane-

jo de interfaces graficas bajo cualquier plataforma que posea una JVM(Java

Virtual Machine)[7].

Los ficheros convencionales ofrecen una abstraccion simple de usar, pero

anticuada si saltamos de los sistemas centralizados a un nuevo concepto, los

sistemas distribuidos. Cuando trabajamos bajo estos nuevos entornos, nos

enfrentamos generalmente a un alto nivel de heterogeneidad. Es, en estos en-

tornos, donde recurrimos a las cajas; estas recogen la simplicidad de manejo

de los ficheros pero, dandonos ademas una semantica de mas alto nivel. Es-

ta mayor expresividad que ofrecen las cajas frente a los clasicos ficheros las

hacen mas adecuadas en entornos distribuidos.

En la actualidad para la generacion de interfaces graficas de usuario en

entornos distribuidos se estan usando sistemas clasicos de entornos centra-

lizados. La cuestion es que ninguno de estos sistemas graficos cumple el nivel

de transparencia exigido para que se considere plenamente distribuido. Con

el servidor que se plantea en este documento se pretende acabar con este

vacio. Pretendemos desarrollar un servicio que ofrezca manejo remoto de es-

tas interfaces con un nivel de transparencia maximo.

La portabilidad en el desarrollo del servicio se ha cuidado hasta un nivel

maximo, dandose no solo a nivel de aplicacion, gracias a la VM de Java,

sino tambien a nivel de comunicacion, ya que, de una forma sencilla pode-

mos ampliar el soporte a distintos protocolos. Esta portabilidad anade una

funcionalidad al sistema; ya no necesitamos a Plan B en un dispositivo para

que este se beneficie de sus caracterısticas.

El objetivo de este proyecto, en resumen, es desarrollar un sistema que

permita a una aplicacion distribuida, que se ejecute bajo Plan B(local o

remota), crear y manejar interfaces graficos de usuario de una forma sencilla.

Capıtulo 1

Introduccion

En cualquier secuencia de ordenes que se tome para programar un orde-

nador la entrada y la salida de datos son conceptos esenciales que se deben

cuidar al maximo, pues determinaran la usabilidad del producto. El desa-

rrollo o implementacion de una aplicacion es bastante similar a como era en

los comienzos: un esqueleto basico y a su alrededor modulos mas o menos

independientes de este primero, que le dotaran de funcionalidad. El esque-

ma del esqueleto y de sus modulos variaba, dependiendo de la aplicacion.

Con la aparicion de las primeras interfaces graficas de usuario, este esque-

ma de desarrollo se ve alterado: el esqueleto de una aplicacion se simplifica,

reduciendose a un bucle o flujo repetitivo, que se encarga de invocar ruti-

nas, alojadas en los modulos complementarios. A este esquema se le puede

denominar programacion orientada a eventos [1]. El desarrollo de las aplica-

ciones que usan interfaces graficos se centra en la implementacion de estos

modulos o librerıas, siendo el esqueleto algo estandarizado.

Con estas primeras interfaces graficas funcionando, tenıamos una apli-

cacion ejecutando en una maquina, que se valıa de un mecanismo grafico, su

interfaz, para comunicarse con el usuario y para que este pudiera comuni-

carse con la aplicacion. Los grandes avances en las comunicaciones y en las

redes de computadores plantearon nuevas situaciones en este campo de la

computacion. Ahora se planteaba la idea de poder separar la aplicacion y la

interfaz grafica en dos maquinas diferentes unidas por una red. Es en este

punto donde podemos enmarcar el objetivo de este proyecto.

Un sistema distribuido[2] transporta la anterior idea de separar procesos

4

CAPITULO 1. INTRODUCCION 5

en diferentes maquinas a su maximo exponente. Este alto grado de disper-

sion hace necesario la utilizacion de un estandar en la comunicacion de esos

procesos, un protocolo de comunicacion. Este protocolo nos da la capacidad

de manejar cualquier recurso remoto de una forma sencilla, pero a la vez

tremendamente funcional. Como se comentara mas adelante, la distribucion

de interfaces graficas y su uso por aplicaciones de forma remota en la actuali-

dad no es tal distribucion, sino que se estan usando mecanismos de interfaces

graficas centralizadas para sistemas que son distribuidos. El servicio, cuyo

desarrollo constituye este proyecto, propone una distribucion muy alta de la

interfaz grafica, ası como una independencia plena de cualquier aplicacion

que requiera usarlo.

En principio se propone desarrollar este servicio para ser ejecutado sobre

Plan B[4]; un sistema distribuido con unas caracterısticas propias muy in-

teresantes. El entorno de ejecucion de las primeras versiones de prueba y de

la ultimas sera diferente, siendo para estas primeras Linux. De igual manera,

el protocolo usado para la depuracion inicial y para las pruebas finales del

servicio sera diferente. Poco a poco, a medida que avance el desarrollo, pre-

tendemos ir girando hacia Plan B sin que esto altere la implementacion del

esqueleto principal del servicio. Con esto pondremos a prueba la portabili-

dad del servidor, ası como la independencia de funcionamiento de la capa de

comunicaciones.

Podemos entonces afirmar finalmente, que se quiere implementar un ser-

vicio para Plan B que ofrezca una interfaz grafica de usuario totalmente

distribuida, con todo lo que esto conlleva.

1.1. Sistemas distribuidos

Un sistema distribuido es una coleccion de computadores independientes

que se aparecen al usuario como un solo sistema[2]

La evolucion de los sistemas operativos desde los comienzos de la com-

putacion y de las redes de comunicaciones, ha hecho que estos dos conceptos

se fusionen dando lugar a un nueva idea de entender los sistemas. Los sis-

temas distribuidos deben de cumplir una serie de caracterısticas que son las

CAPITULO 1. INTRODUCCION 6

que por otra parte les aportan toda su potencia. Estos sistemas estan com-

puestos por una serie de nodos o dispositivos que pueden ser totalmente

heterogeneos, pero de cara a un usuario del sistema, este debe aparecer como

una sola maquina, un sistema sencillo. Ademas, a nivel de hardware, cada

dispositivo o nodo que forma el sistema debe ser completamente autonomo.

Para conseguir este soporte a dispositivos muy diferentes entre sı, los sistemas

distribuidos suelen organizarse en base a una serie de capas logicas ademas

de las capas tradicionales (ver [5]). Entre las capas superiores (aplicaciones)

y las mas inferiores (sistema operativo local) ahora situamos tıpicamente un

nuevo nivel o capa de Middleware.

Otra caracterıstica importante es que deberıan ser facilmente expandibles

o escalables. Debemos poder anadir nodos, incluso en gran numero, sin que

el funcionamiento del sistema sufra cambios.

1.2. Interfaz de usuario

Una interfaz de usuario (UI ) es una estructura utilizada en la comu-

nicacion entre un usuario y el ordenador que ejecuta la aplicacion. Estas

interfaces de usuario tradicionalmente conllevaban implıcitamente un esque-

ma de control de flujo para la aplicacion: entrada de datos, procesamiento

y salida de resultados. Con el tiempo estas interfaces comenzaron a adquirir

un aspecto grafico. Las aplicaciones se valıan de una serie de objetos, casi

siempre ofrecidos por el entorno de ejecucion, para representar de una for-

ma grafica lo que hasta ese momento habıa sido como mucho una ((lınea de

comandos)). Estos elementos tambien se denominan widgets, termino que de-

fine genericamente a los controles que componen una interfaz grafica, como

botones, entradas de texto, scrolls y similares.

Esta nueva forma de interactuacion usuario-maquina trae consigo otro

esquema de control de flujo para la aplicacion. Ahora la aplicacion ya no

espera de forma tan estatica una entrada de datos, sino que simplemente se

limita a atender al usuario, cuando este provoca un evento. Un evento no

es mas que la consecuencia del manejo o uso de un widget por un usuario.

La rutina encargada de la creacion y manejo de widgets avisara a la apli-

cacion que se ha producido un evento en uno de ellos, para que esta actue

CAPITULO 1. INTRODUCCION 7

en consecuencia. Puede comportarse interrumpiendo su ejecucion y dando

respuesta a ese evento,o quizas, encolandolo para atenderlo mas tarde. La

programacion orientada a eventos[1] ha supuesto un gran avance sobre las

interfaces de usuario no graficas y ocupara una parte importante en el diseno

y desarrollo de este proyecto.

Un ejemplo de interfaz grafica es la GUI (Graphical User Interface) de

UNIX[6]. Cualquier aplicacion ejecutada sobre UNIX puede hacer uso del

Sistema X Windows, este sera el encargado de representar los widgets corres-

pondientes y de gestionar su uso. Plan B tambien necesita estas rutinas para

la creacion de estas interfaces y el manejo de sus eventos. Es aquı donde se

centra el desarrollo de este proyecto.

1.3. Uso distribuido de las interfaces graficas

de usuario

Llegados a este punto tenemos programas ejecutando sobre maquinas y

que se sirven de librerıas graficas para generar interfaces de comunicacion en-

tre el usuario y ellos mismos. Captaran, pues, a traves de estas librerıas toda

la informacion entrante y podran mostrar al usuario la informacion saliente.

Hemos separado la aplicacion de la maquinaria grafica, aunque sin salirnos

del entorno local a la maquina. Deseamos aumentar un nivel mas esta se-

paracion entre procesos y situarlos en maquinas diferentes, dotandolas de un

sistema de comunicacion. Necesitamos hacer saber a la aplicacion que ahora

debe redirigir sus peticiones a la librerıa grafica remota y no a su librerıa

local (ver figura 1.1). El problema es que, aunque esto es posible, no hay

ningun mecanismo que ofrezca una total transparencia para esta operacion.

No existen en los sistemas actuales ninguna interfaz distribuida como tal sino

mas bien un uso distribuido de las interfaces graficas locales, que no es para

nada lo mismo.

Siguiendo con el mismo ejemplo propuesto arriba, varias maquinas en una

red que usen X Windows pueden hacer uso de las rutinas de otro servidor

de X que este accesible en la red, modificando correctamente el ((entorno del

sistema)),esto es un claro uso distribuido de una interfaz grafica clasica. Una

CAPITULO 1. INTRODUCCION 8

verdadera interfaz grafica distribuida debe ofrecer una operacion como la

anterior, sin necesidad de ningun cambio significativo en ese entorno (trans-

parencia).

Figura 1.1: Uso distribuido de una interfaz grafica de usuario

Con nuestro servicio dotaremos al sistema de una caracterıstica funcional

muy interesante: no distinguir entre recursos locales y remotos. El servidor

que se desea desarrollar dara una total transparencia a la operacion antes

comentada. Cualquier aplicacion podra crear, borrar o usar remotamente

un widget con la misma facilidad que lo harıa de forma local, sin modificar

ninguna variable de entorno u otros cambios en el sistema. Operaciones co-

mo un cambio de dispositivo de visualizacion en tiempo de ejecucion (p.ej

del monitor a la pantalla del movil), por parte del programa, pasarıan a ser

una operaciones triviales. Estas operaciones se pueden complicar aun mas,

si tenemos en cuenta que no solo podemos querer cambiar de dispositivo de

visionado, sino que ademas podrıamos querer abortar la visualizacion o mul-

tiplicarla a varios dispositivos y todo ello en tiempo de ejecucion. Esto en

la actualidad es imposible con los sistemas clasicos de interfaces de usuario.

Otra caracterıstica ganada con el uso de este servicio es la heterogeneidad de

dispositivos. Ya no necesitamos saber en que dispositivo se esta visualizando

nuestros widgets, ni siquiera donde esta situado; se gestionaran a traves del

servicio independientemente de la plataforma de visionado.

CAPITULO 1. INTRODUCCION 9

1.4. Plan B

Los entornos de computacion han evolucionado considerablemente desde

los inicios. En la actualidad, los recursos y los sistemas de comunicacion para

interconectarlos se reparten el protagonismo en estos entornos. Ademas se da

la situacion de que estos recursos, aun perteneciendo a un mismo entorno,

pueden ser completamente heterogeneos, incluso, aparecer y desconectarse

dentro de una misma sesion de uso. La complejidad de manejo de estos en-

tornos ha hecho necesario el avance en el desarrollo de nuevos sistemas y es

en este punto donde aparece Plan B.

Plan B es un nuevo sistema operativo que simplifica la implementacion

y ejecucion de aplicaciones en estos entornos tan variantes. Para conseguir

esto se apoya en una nueva abstraccion, la caja[3]. Estas cajas son contene-

dores de bytes. Una caja puede contener dentro de ella mas cajas ademas.

La caja representa un paso mas sobre la idea clasica de fichero. Estas cajas

son la pieza clave desde donde se construye el sistema de ficheros de Plan B

y, por lo tanto, desde donde parte todo el sistema. Hay que insistir en la idea

del sistema de ficheros como cimiento fundamental del sistema, pues como

se explica mas adelante, para Plan B ((todo es una caja)). Esta idea es un

punto en comun con otros sistemas que han inspirado a Plan B como Plan 9

o inferno.

Los principios fundamentales con los que se ha construido Plan B son:

Todos los recursos se abstraen como cajas. Esto implica que toda la

funcionalidad sobre estos pasa por el manejo de las cajas que los re-

presentan.

El sistema opera de igual manera con cajas locales y remotas siguiendo

un mismo protocolo llamado Bp (ver seccion 1.4).

Cada aplicacion posee un espacio de nombres independiente y tiene

poder para modificarlo.

El acceso a las cajas se realiza a partir de su nombre. En Plan B desa-

parece la idea de descriptor.

CAPITULO 1. INTRODUCCION 10

Cabe destacar de la anterior lista, la potencia que otorgan al sistema

la fusion del primer y segundo punto. Podemos recoger de estos la idea de

que, si Plan B accede tanto a cajas locales y remotas de la misma manera y

que para el todos los recursos se abstraen en cajas, tenemos que bajo Plan

B disponemos de una simplicidad de acceso y manejo de recursos remotos,

similar a la de recursos locales. Basandonos en esta idea se pretende cons-

truir un servicio de widgets, de manera que, para este caso, se tratara a cada

widget como una caja independiente. Este proceso servidor permanecera a

la escucha de peticiones y gestionara esos widgets segun estas peticiones.

Creando un servicio de estas caracterısticas dotaremos al sistema de una

gran potencia de representacion grafica sobre multiples arquitecturas. No

sera necesario disponer de un kernel de Plan B arrancado en todos los dis-

positivos del entorno, ya que, implıcitamente, estamos exportando el sistema

de cajas a cada maquina que posea nuestro servicio.

Con la combinacion de Plan B y este servidor de widgets, el complejo

escenario propuesto al comienzo se reduce a un kernel de Plan B creando

y manejando widgets, que, a efectos de Plan B, son cajas sobre cualquier

plataforma. Todo el conjunto se simplifica aun mas para el desarrollador de

Plan B, si tenemos en cuenta el sencillo repertorio de operaciones del proto-

colo Bp.

1.4.1. Protocolo Bp

El protocolo Bp es la interfaz funcional entre el kernel del plan B y las

cajas. La localizacion de estas cajas resulta indiferente para su manejo, gra-

cias a la utilizacion de este protocolo, tanto para cajas locales como remotas.

El protocolo Bp posee un sencillo repertorio de peticiones, que facilita en ex-

tremo el manejo de las cajas y, por ende, de los recursos de nuestro entorno

distribuido. El formato de los mensajes Bp esta tambien muy simplificado,

compuesto solo por una pequena cabecera, una estructura con la informacion

de la peticion y una estructura con la informacion devuelta en la respuesta.

Estas peticiones son autocontenidas, con lo que conseguimos evitar que el

servidor mantenga estado y eliminamos el concepto de descriptor de caja;

ya no necesitamos mantener una conexion abierta con un recurso hasta que

terminamos de usarlo (close).

CAPITULO 1. INTRODUCCION 11

La distribucion del sistema, a traves de nodos interconectados entre sı,

hace necesario la implementacion de servicios que gestionen esas peticiones

Bp. Esta es la motivacion principal de nuestro servidor de widgets. De acuer-

do con una semantica establecida (ver manual de ui [4]) nuestro servidor nos

dara un control total sobre la interfaz grafica que deseemos, ya sea remota

o local. Por ejemplo, podemos generar en un dispositivo remoto, dada una

secuencia de instrucciones como la siguiente, un boton de aceptacion y el

marco que le contenga:

make /b/ui/row:marco

make /b/ui/row:marco/button:aceptar

Los eventos producidos por el usuario se recogen de forma similar reco-

giendo el contenido sobre la caja encargada de este menester:

get /b/ui/events/row:marco

Esta instruccion rescata los eventos producidos por cualquier widget alo-

jado en el contenedor, llamado marco de tipo fila. Como se puede ver, con-

seguimos interactuar, de forma totalmente transparente, con una interfaz

grafica, que puede estar alojada en cualquier tipo de dispositivo que ejecute

nuestro servicio (PDA, videowall, lavadora con pantalla LCD, etc).

1.5. Java y AWT

Para el desarrollo del servidor se ha optado por elegir un lenguaje orienta-

do a objetos como Java. La orientacion a objetos es un concepto en el que los

protagonistas de este proyecto, los widgets y controles graficos, se desenvuel-

ven a la perfeccion, siendo su manejo con este tipo de lenguajes muy sencillo.

En la eleccion de Java, entre otros lenguajes de este mismo paradigma, ha

tenido mas peso otra razon: la portabilidad. Desde que se plantea la idea de

desarrollar un servidor de estas caracterısticas, la cuestion de la portabilidad

se cuida al maximo. Los entornos en los que el sistema funcionara seran varia-

dos y heterogeneos, al igual que los dispositivos que poblaran esos entornos.

Por esta razon necesitamos hacer funcionar nuestro servidor en todo tipo

CAPITULO 1. INTRODUCCION 12

de plataformas con soporte grafico. La JVM (Java Virtual Machine) aporta

un nivel aceptable de independencia sobre la arquitectura necesaria[7], sin

olvidar que aun ası hay plataformas como Symbian donde este API no es

soportado.

El soporte grafico ha sido una decision crıtica. Conservar la portabili-

dad del servicio, usando librerıas graficas nativas en cada dispositivo es una

cuestion de vital importancia. En este punto se ha decidido usar AWT (Ab-

stract Window Toolkit)[8]. Esta librerıa grafica de Java, a pesar de ser de

relativa antiguedad, aporta unas caracterısticas que la hacen encajar a priori

perfectamente en los requisitos del proyecto. Los objetos de AWT pueden

ser usados durante el desarrollo de una aplicacion grafica, sin necesidad de

saber a priori el dispositivo donde va a ejecutarse dicha aplicacion. Esto es

posible gracias a un conjunto de clases llamadas peers [8]. Cada JVM posee

unos peers nativos diferentes dependiendo de la plataforma donde ejecute;

por eso, cuando una clase AWT quiere visualizarse invoca implıcitamente

metodos de estos peers. El unico problema que se observa en este sistema de

visualizacion, es que esta cambiara ligeramente, dependiendo del peer que

use. Por ejemplo, un boton puede visualizarse de forma diferente (color, for-

ma,etc) dependiendo del peer usado. No hay que olvidar que estos peers usan

la librerıas graficas nativas de cada dispositivo. La combinacion de Java y

AWT, permitira al servidor mantener un aceptable grado de portabilidad y

compatibilidad con bastantes plataformas y arquitecturas.

Capıtulo 2

Objetivos

Como ya se ha adelantado anteriormente (ver seccion 1.3) actualmente

existen sistemas para la distribucion de interfaces graficas que no cumplen los

criterios de transparencia exigidos en un sistema distribuido. De este punto

se extrae el objetivo global que queremos alcanzar en este proyecto: dar

soporte grafico a Plan B,un sistema distribuido, respetando las condiciones

de transparencia exigidas.

Figura 2.1: Esquema de funcionamiento del servicio

Tenemos tambien que cualquier mandato del nucleo del sistema se dis-

tribuira por una red de comunicacion que interconecta todos los dispositivos

que forman este sistema, es por ello que necesitaremos una aplicacion, nuestro

servidor, que permanezca constantemente a la escucha de esa red de comu-

nicacion. Ya disponemos entonces de las piezas claves sobre las que cimentar

13

CAPITULO 2. OBJETIVOS 14

nuestro diseno y posterior desarrollo: un nucleo que envıa peticiones, una red

de comunicacion que transporta esas peticiones y un servicio que recogera las

peticiones del nucleo y con ellas gestionara las cajas almacenadas en ese dis-

positivo; en nuestro caso esas cajas contendran controles graficos. Este fun-

cionamiento se ilustra en la figura 2.1

2.1. Descripcion del problema

El problema se puede enunciar en terminos muy simples: una maquina

ejecuta una aplicacion y en un momento dado, esta aplicacion quiere dejar

de usar un periferico grafico concreto para usar otro, tal como se ilustra en la

figura. Si pensamos en terminos de aplicaciones, actualmente es relativamente

sencillo redireccionar la salida de datos de un proceso de un periferico grafico

a otro.

Figura 2.2: Cambio de visualizador en tiempo de ejecucion

Si pensamos en terminos de programador, ¿puede este generar un control

grafico (un boton, un menu, etc) en el entorno grafico de otra maquina?.

¿Que ocurre si un usuario tras crear una interfaz grafica decide visualizarla

en ambos dispositivos? o ¿una parte de ella en uno y otra parte en el otro?

(ver figura 2.2). Podemos seguir complicando la casuıstica de ejemplo y siem-

pre llegarıamos a la siguiente conclusion: crear y gestionar interfaces graficas

CAPITULO 2. OBJETIVOS 15

de usuario en uno o varios entornos remotos es cuanto menos complicado.

En este punto se centra el desarrollo del servidor. Gracias a este servicio

podremos montar[6] virtualmente sobre nuestro sistema de ficheros la caja

raız del servidor. A partir de ahı podremos gestionar cualquier widget como

si fuera una caja, con la sencillez de manejo que implıcitamente esto conlle-

va. Operaciones como las anteriormente mencionadas se reducirıan a ejecutar

unas pocas operaciones sobre las cajas concretas (make,list,put, etc).

2.2. Objetivos a cumplir

El objetivo de este proyecto es el de desarrollar un servicio, que ges-

tione widgets u controles graficos. Este servidor implica una aproximacion

a la creacion y gestion de interfaces graficos completamente distribuida (ver

apartado 1.3). Contra el iran dirigidas las peticiones sobre un tipo concreto de

caja, los widgets. Estas cajas del sistema son las piezas con las que formare-

mos interfaces graficas completas en cualquier dispositivo grafico. Guardan

el estado de estos objetos en cada momento y con ellas podemos realizar

las mismas operaciones que con cualquier caja. Para acceder a estas cajas

debemos realizar una operacion de montado del sistema de cajas del servidor

sobre nuestro sistema de ficheros.

Esta es la idea general del proyecto: el servidor permanece a la escucha de

peticiones y, cuando estas llegan, las transforma en operaciones de manejo de

controles graficos y envıa, en la mayorıa de los casos, un mensaje de respuesta.

Para la comunicacion con el servidor es necesario seguir un protocolo,

entendido tanto por el servicio como en la aplicacion cliente. Para evitar que,

en una primera fase del desarrollo, nuestro servicio interactuara con el sis-

tema, experimental y quizas inestable, se ha optado por la implementacion y

el uso de un protocolo mas sencillo, desarrollado para la ocasion; el protocolo

STRp. Posee una interfaz identica a Bp (ver seccion 1.4.1), aunque con un

menor numero de comandos. A medida que el desarrollo avance se pretende

integrar de una forma limpia el protocolo Bp, demostrando ası la indepen-

dencia entre el mecanismo central del servicio y el protocolo usado para la

comunicacion. Sin entrar a fondo en temas de diseno por ahora, sı diremos

CAPITULO 2. OBJETIVOS 16

que hemos dotado al servicio de una capa de comunicaciones en donde se

enmarca el contexto del protocolo. La idea inicial es que podamos tener va-

rios protocolos implementados y que la conmutacion entre ellos no suponga

cambios significativos en el resto de las capas del servicio.

Para la depuracion en esta fase, se usara una aplicacion cliente que integra

el protocolo STRp. Este sencillo cliente empaqueta los mensajes de peticion

en forma de strings, los envıa a nuestro servicio usando STRp y espera la

respuesta. Este cliente, llamado bpsh, se ha disenado en forma de shell de

comandos, desde el cual podremos manejar a traves de un sencillo repertorio

de ordenes una interfaz grafica remota.

En una segunda fase del desarrollo se ha querido comenzar a integrar el

protocolo bp. Para que esta operacion resulte menos traumatica se optara por

no usar Plan B aun, sino una version portada de sus librerıas de Bp a ANSI-

C, denominadas ANSI-Bp. Esto nos permite afianzar la implementacion del

servicio en un entorno mas estable y conocido. Se ha usado el mismo cliente

que en el caso anterior con esta nueva librerıa.

Como se puede ver, la depuracion del servidor se ha basado en la imple-

mentacion de estos dos protocolos y del shell cliente antes de la completa

integracion con Plan B. Estos protocolos se asemejan cada vez mas a su mo-

delo final: las librerıas de Bp de Plan B.

Capıtulo 3

Metodologıa y Requisitos

Como metodologıa de diseno se ha seguido una en espiral u orientada a

prototipos, de tal manera que se han ido implementando versiones, una tras

otra siempre apoyadas en su anterior. Las sucesivas versiones se han agru-

pado en tres prototipos fundamentales. Esta division se ha hecho en base a

nuevos anadidos o modificaciones sobre la anterior version.

3.1. El modelo en espiral

La metodologıa en espiral basa su comportamiento en la division del

proyecto en n prototipos o rondas de una espiral virtual. Se comienza con

unos requisitos iniciales, se plantean en base a estos un objetivos y se desarro-

lla una version inicial que es probada y validada. Con estos pasos habrıamos

completado una ronda completa de la espiral y tendrıamos un prototipo pri-

mitivo, pero completamente funcional en base a la especificacion inicial.

Los sucesivos cambios y anadidos en los requisitos implican vueltas suce-

sivas a la espiral o nuevos prototipos basados en sus anteriores. Este modelo

en espiral posee importantes ventajas sobre otros modelos de diseno:

Centra su atencion en la reutilizacion de componentes y eliminacion de

errores descubiertos en fases anteriores.

Integra desarrollo con mantenimiento.

17

CAPITULO 3. METODOLOGIA Y REQUISITOS 18

Figura 3.1: Representacion del modelo en espiral

3.2. Requisitos

Los objetivos generales del proyecto ya han sido expuestos anteriormente

(ver seccion 2.2), pero los requisitos especıficos en los que se basa el diseno

y el posterior desarrollo se describiran a continuacion.

Como ya se ha explicado con anterioridad, nuestro servicio transfor-

mara peticiones de otros dispositivos en objetos visualizables. Lo primero

que se ha necesitado era definir las caracterısticas de estos objetos, forma de

nombrado, como se relacionan entre sı, cuales son sus tipos, etc. Tras definir

todos los widgets que se querıan servir en una version inicial, estos se divi-

dieron en dos tipos basicos, contenedores y componentes.

Un widget de tipo contenedor tiene como funcion albergar en su interior

otros widgets. Los contenedores que se han definido e implementado hasta

el momento son tres: row, col y menu. Sus diferencias tan solo radican en la

visualizacion de los widgets que contienen:

CAPITULO 3. METODOLOGIA Y REQUISITOS 19

row

Este contenedor muestra sus widgets en una fila, alineados de izquierda

a derecha.

col

El contenedor col dibuja sus widgets en pantalla en forma de columna,

de arriba a abajo.

menu

Este widget contenedor posee una similitud al col por su visualizacion

(en columna) aunque muestra en su parte superior su nombre. Ademas

este contenedor solo admite algunos tipos de widgets.

Los componentes, por tanto, no pueden albergar ningun otro widget en

su interior. Cada widget de tipo componente debe ser creado por obligacion

dentro de un contenedor. La mayoria de estos componentes llevan asociado

un estado del cual depende su representacion en pantalla:

button

Con el representamos un boton. Su estado puede ser pressed o release.

entry

Este componente sirve tanto para recibir texto del cliente como para

mostrarselo. Se representa en forma de caja de texto editable y su

estado es el texto que contiene.

radio

Equivalente al boton pero solo podra ser creado dentro del widget menu.

check

Similar al radio, con la diferencia de que si tenemos varios de estos

dentro de un menu, solo uno de ellos puede estar pulsado (pressed).

gauge

Este widget representa a una barra deslizante, con un valor segun su

posicion (de 0 a 100). Su estado es el valor dibujado en pantalla.

label

Su funcion es la de mostrar un texto no editable en pantalla. Su estado

es el texto que muestra.

CAPITULO 3. METODOLOGIA Y REQUISITOS 20

image

Este componente muestra una imagen en pantalla. El estado de este

son los bytes de la imagen.

rectangule

De forma similar al anterior, este widget tambien muestra una imagen

en pantalla con la diferencia de que este widget escucha eventos de

raton.

Cabe destacar los checks y radios, estos componentes solo pueden ser

creados dentro de un contenedor de tipo menu, pero ademas un widget de

tipo menu solo podra contener estos dos componentes. Cuando creamos un

widget, determinamos el tipo de este a traves de su nombre. De esta manera

todos los nombres de widget siguen el siguiente formato: tipo:nombre.

Para la gestion de eventos se ha usado un modelo de propagacion. Los

componentes son los unicos que tienen definidos eventos. Cuando un compo-

nente recibe un evento se genera un mensaje que automaticamente sera tras-

pasado a su contenedor, este comprobara si hay una peticion en curso de

lectura de eventos sobre el, en cuyo caso lo entregara. En caso de que nadie se

haya interesado por sus eventos enviara el mensaje a su contenedor que reali-

zara la misma comprobacion. Tenemos entonces un mensaje que se ira pro-

pagando desde el componente a los superiores. En el caso de que no haya

ninguna peticion de lectura de eventos, el mensaje se acola en el contene-

dor del componente que produjo el mensaje. Para acceder a los eventos

de un contenedor usaremos la caja /events. Se realizara una lectura sobre

/events/nombre-del-contenedor para recuperar los eventos ocurridos sobre los

widgets situados bajo este contenedor (este procedimiento es ampliado en el

capıtulo de arquitectura).

La interfaz de comunicacion del servicio es la ofrecida por el protocolo

Bp[4]. Nuestro servicio debe soportar las siguientes peticiones:

make

Genera una caja. Esta peticion contiene el nombre de la caja a crear y

no devuelve ninguna respuesta.

get

Obtiene el contenido de una caja. Para conseguir el contenido de una

CAPITULO 3. METODOLOGIA Y REQUISITOS 21

caja enviamos una peticion de get con el nombre de la caja. Nuestro

servicio nos devolvera un array de bytes con el contenido de la caja.

put

Coloca un contenido en una caja. Junto con la peticion de put se envia

el nombre de la caja y los bytes que deseemos actualizar en ella. No

obtenemos repuesta alguna.

list

Lista las cajas contenidas dentro de una caja. Esta peticion se lanza

junto con el nombre de la caja cuyo contenido queramos listar y la

longitud maxima admitida en nuestro buffer, la respuesta debera adap-

tarse a esta longitud. Se devuelve un string con los nombres de las cajas

contenidas.

delete

Elimina una caja, su contenido y todas las demas cajas contenidas

en ellas. Se Lanza tambien con el nombre de la caja y no devuelve

respuesta.

info

Devuelve los metadatos asociados a una caja. Esta peticion no se in-

cluye en el protocolo STRp ya que devuelve una estructura con los

metadatos que solo ha sido desarrollada durante la integracion del pro-

tocolo Bp, en la fase final del proyecto.

chinfo

Actualiza estos metadados. Con esta ocurre lo mismo que con su ante-

rior y no ha sido incluida en el protocolo STRp.

Capıtulo 4

Arquitectura y diseno

Dedicaremos este capıtulo en extendernos a fondo en la arquitectura es-

tructural del servicio. Para ello seguiremos un planteamiento descendente,

planteando primero el funcionamiento de los elementos mas superficiales para

luego pasara al analisis en profundidad de estos.

4.1. Introduccion

El servidor atiende una conexion que transporta peticiones. Cada peti-

cion es enviada implıcitamente hacia el sistema de visualizacion, aunque es

nuestro servicio quien la recibe y la procesa (figura 4.1).

Figura 4.1: Esquema con el funcionamiento del servicio

Para el procesamiento total de la peticion y la posterior gestion del sis-

tema grafico nativo, el servicio se vale de tres paquetes. Estos encapsulan

toda la funcionalidad del servidor de la siguiente manera:

22

CAPITULO 4. ARQUITECTURA Y DISENO 23

net

Aporta la funcionalidad a nivel de comunicaciones. Esta clase dara el

soporte a los distintos protocolos.

sys

Este paquete implementa las clases principales del servidor para el

manejo de cajas.

wdg

Almacena todas las clases con soporte grafico. Los widgets que servimos

estan aquı implementados.

Figura 4.2: Arquitectura basica en tres modulos

Cuando recibimos una peticion a traves de una red de comunicaciones,

antes de iniciar cualquier proceso, debemos interpretarla. Debemos de con-

vertir un ((Un flujo de bytes)) en algo entendible para nuestro servicio. De esta

operacion se encargara el paquete net. Para dotar de un soporte completo y

portable, este paquete se subdividira a su vez en paquetes mas especıficos,

uno por cada protocolo, soportado por el servicio; por ahora tan solo se ha

desarrollado y probado el paquete net.bp.

Si ya disponemos de una peticion en un formato entendible por nuestro

servicio, debemos procesarla. Esto implica el manejo de cajas o lo que es

lo mismo creacion, borrado y modificacion. El paquete sys implementa dos

abstracciones fundamentales para estas operaciones: la caja y el sistema de

cajas. Estos dos elementos se consideran, por su importancia, como el nucleo

de la aplicacion. La caja aporta la funcionalidad de este elemento (ver apar-

tado 1.4) al servidor. El sistema de cajas por su parte nos ofrece mecanismos

y estructuras para el correcto almacenamiento y manipulacion de estas (ver

CAPITULO 4. ARQUITECTURA Y DISENO 24

figura 4.5).

Como ya se ha comentado anteriormente cada caja mantiene un contexto

grafico en su estado. Para dar soporte a dicho contexto disponemos del paque-

te wdg. Este almacena una coleccion de objetos representables graficamente

gracias al paquete grafico AWT (ver seccion 1.5). Ademas dentro de wdg

podremos encontrar el concepto de escuchador o listener. Estos escuchadores

tienen como funcion basica recoger y manejar eventos de la interfaz.

4.2. Prototipo 1: Servidor de widgets

Con este primer protototipo se ha intentando un primera aproximacion a

la gestion remota de widgets. Usando como protocolo de comunicacion STRp

se quiso ofrecer todos los widgets propuestos en la pagina de manual de ui

explicados en 3.2. Este protocolo se ha disenado e implementado para la

ocasion, posee un repertorio de peticiones similar al del protocolo Bp y de

esta manera la interfaz del servicio se ha mantenido fija desde el comienzo

hasta el final del desarrollo. Para manejar el empaquetamiento de peticiones

se ha implementado un sencillo shell que realiza las funciones de cliente y

depurador.

4.2.1. Diseno del protocolo STRp

Este prototipo esta orientado a ganar experiencia con el paquete grafi-

co AWT, de ahı que se use el protocolo STRp, facil de usar y sin posibles

errores internos, que demoraran las pruebas y la depuracion. El protoco-

lo STRp esta basado en el envio y recepcion de strings (de ahı su nombre

STRing Protocol). Tal y como ilustra la figura 4.3, cuando desde nuestro shell

tecleamos una peticion el buffer de caracteres es enviado tal cual al servidor.

En el servicio se recibe el buffer de caracteres y se procesa caracter a caracter.

Gracias a este metodo reducimos en gran medida la complejidad del paquete

net y de los procesos de desaplanado[2] y procesamiento de la peticion.

El repertorio de las peticiones ofrecidas por STRp es algo mas reducido

que, el que mas tarde ofrecera el protocolo Bp y que es descrito en los requi-

sitos del proyecto. Esto es ası debido a que en ese primer prototipo aun no

CAPITULO 4. ARQUITECTURA Y DISENO 25

Figura 4.3: Envio de una peticion usando STRp

necesitamos un funcionamiento pleno del nivel de comunicacion del nuestro

servicio, tan solo dotar a este de una interfaz para crear y gestionar widgets.

A continuacion se muestra la estructura de los mensajes que ofrece STRp.

Cabecera Cuerpo Respuesta

Make nombre OK

Delete nombre OK

Get nombre contenido

Put nombre contenido OK

List nombre string

Como se observa todas las peticiones requieren de un campo nombre, con

el nombre de la caja sobre la que se quiere realizar la operacion, ademas en

las peticiones get y put, el campo contenido solo puede estar formado por

caracteres, debido al diseno interno del protocolo basado en strings. Todas

las respuestas devolveran una respuesta en forma de un string. Este puede

estar formado por la informacion devuelta por el servicio, en el caso de list o

get o por la cadena ((OK)) en los demas casos. Si una peticion no es procesada

correctamente se devuelve un string con la cadena ((ERROR)).

4.2.2. Diseno del widget

Lo primero que se ha necesitado ha sido un primitivo servicio que reac-

cione de alguna forma ante algun tipo de peticion remota. En este prototipo

ya se comienza a esbozar el motor interno del servidor, que procesa secuen-

cialmente la peticion desde su llegada por la red hasta la creacion del control

grafico. El uso de STRp reduce la complejidad del nivel de comunicacion del

CAPITULO 4. ARQUITECTURA Y DISENO 26

servicio. De esta manera los esfuerzos se han centrado en la manera de como

crear el widget y como almacenarlo junto a los demas que fueramos creando.

En el diseno de un widget se ha contemplado todos los elementos propios de

la caja y ademas otro atributo que le permite poseer un aspecto grafico con-

creto. El anadido de este atributo caracterıstico ha sido el principal problema

de diseno de esta primera version. Los widgets se han dividido en contene-

dores y componentes, donde los primeros tienen como funcion albergar a los

segundos. Se ha descrito detalladamente los widgets y sus peculiaridades en

la pagina de manual de Plan B y en los requisitos del proyecto (ver seccion

3.2). Para la funcion de visualizacion se ha usado el paquete AWT de Java

(ver apartado 1.5).

Figura 4.4: Correspondencia entre los arboles logicos que se han formado

Cada widget lleva aparejado un objeto de este paquete con la dificultad

de manejo que esto entrana y que paso a explicar: al crear una caja dentro

de otra estamos generando de alguna manera un grafo en forma de arbol,

donde de cada nodo pueden colgar nodos hijos que se corresponden con las

cajas que contiene; estas cajas internas tiene a su vez su control AWT propio

que ha de ser incluido tambien en el control AWT del padre, esto provo-

CAPITULO 4. ARQUITECTURA Y DISENO 27

ca la aparicion de otro arbol paralelo, como se ve en la figura 4.4, formado

solo por los controles AWT de cada caja, y una correspondencia entre ambos.

4.2.3. Almacenando widgets

El almacenamiento de estas cajas se realiza gracias al sistema de cajas

(systemBox). Este objeto almacena y gestiona las referencias de las cajas

creadas en el espacio de memoria del servidor. Cuando una caja es creada,

insertamos en el sistema de cajas una referencia a esta. De igual manera,

cuando borramos una caja se elimina su referencia del sistema de cajas. Si

algun objeto desea manejar una caja debera pedirle al sistema de cajas una

referencia a esta, ya que el sistema de cajas es el unico administrador de estas

referencias. Para una mayor compresion de este objeto, ilustramos un caso

real. Primero creamos dos cajas, una fila y un boton contenido en esta:

make /b/ui/row:marco

make /b/ui/row:marco/button:aceptar

La figura 4.5 muestra el estado esquematico del sistema de cajas y de los

paquetes del servicio.

Figura 4.5: Interaccion entre el paquete sys y el paquete wdg

CAPITULO 4. ARQUITECTURA Y DISENO 28

4.3. Prototipo 2: Servidor de widgets y

eventos

Comenzamos el diseno de esta version sobre un prototipo que consigue

recibir peticiones, crear y gestionar widgets. Por este lado hemos llegado a la

especificacion final. Quedan aun ası importantes puntos que hemos dejado de

lado y que abordaremos en esta segunda fase. El objetivo de este prototipo es

anadir toda la funcionalidad respecto de los eventos, su recogida y posterior

notificacion al usuario.

4.3.1. Proceso de gestion de eventos

Figura 4.6: Si se realiza una peticion de lectura sobre el contenedor el evento se

entrega

Los eventos son los protagonistas de las interfaces graficas de usuario.

Cuando un usuario interactua con un control grafico produce un evento que

CAPITULO 4. ARQUITECTURA Y DISENO 29

le es trasladado al motor de la interfaz para que ejecute la accion pertinente.

El problema, que rapidamente advertimos, es que, en nuestro caso, el widget

esta en un ((sitio diferente)) al del motor que lo gestiona; por ello debemos

conseguir un sistema para almacenar y transportar estos eventos. Siguien-

do la especificacion de ui (ver seccion 3.2) tenemos que solo los componentes

pueden producir eventos; un boton puede producir un evento como ((pressed))

al igual que un radio o un check, una fila o un menu no podran producir even-

tos. Los contenedores solo se encargan de almacenar estos eventos. Cuando

se produce un evento, el componente que lo produce lo envıa a su contene-

dor, donde sera almacenado, en el caso de que nadie este interesado en el.

Si deseamos saber los eventos que se han producido, debemos realizar una

peticion de lectura de eventos sobre un contenedor concreto; esto provoca

una recoleccion de todos los eventos guardados en los contenedores, incluidos

en el, para que sean enviados al peticionario (ver figura 4.6). Las peticiones

de lectura de eventos se realizan a traves de la caja /events.

Figura 4.7: El evento es encolado en el contenedor que inicio la propagacion

Para realizar una peticion de lectura de eventos sobre un grupo de widgets

deberıamos realizar la peticion en su contenedor: get /events/row:fila/col:columna.

Una llamada como la anterior devolverıa todos los eventos producidos bajo

CAPITULO 4. ARQUITECTURA Y DISENO 30

el contenedor /row:fila/col:columna. Es interesante destacar que las lecturas a

traves de la caja /events son bloqueantes, de tal forma que, si la llamada no

devuelve ningun evento, dejara la conexion bloqueada hasta que tengamos

algun evento recolectado.

El sistema de gestion de eventos sigue un modelo de propagacion. Los

mensajes de eventos son propagados a contenedores superiores y en el caso

de que nadie realice una lectura de eventos sobre ellos, son encolados. Cuando

un componente recibe un evento lo notifica inmediatamente a su contenedor

y este comprueba si hay interes por parte del usuario sobre los eventos de los

widgets que almacena, en caso afirmativo el contenedor recolecta los eventos

encolados de todos los contenedores almacenados bajo el y los entrega junto

con los suyos (ver figura 4.6). Como se puede ver en dicha figura ademas,

se devuelve TRUE para indicar que el evento ha sido entregado. En caso

de que nadie haya mostrado interes propaga el mensaje a su contenedor,

para que este haga lo mismo. Al final de la cadena, llegamos al contenedor

raiz y es en este instante, cuando el contenedor que inicio la propagacion se

da cuenta de que nadie ha mostrado interes por su evento debido a que el

proceso de notificacion de eventos devuelve FALSE. En este caso el evento

es situado en la cola del contenedor que inicio la propagacion (ver figura 4.7).

Un elemento esencial en el sistema de eventos es el escuchador. Este ob-

jeto inicia todo el proceso capturando el evento. Cuando creamos un widget

le adosamos un objeto escuchador y este permanecera alerta capturando los

eventos que se produzcan. Estos escuchadores se han alojado en el paquete

wdg. La figura 4.8 muestra como se inserta un escuchador durante la creacion

del componente de tipo button. En dicha figura se muestra que tras la peti-

cion de creacion de las cajas (1), a la caja boton se le inserta un objeto

escuchador que permanecera a la escucha de eventos procedentes del sistema

grafico nativo (2).

CAPITULO 4. ARQUITECTURA Y DISENO 31

Figura 4.8: Al ser creado el widget button se le adosa un objeto escuchador

4.4. Prototipo 3: Servidor de widgets y

eventos sobre Bp

En esta tercera fase se ha comenzado a integrar el protocolo bp. Para

depurar esta version se han usado las librerıas ANSI-Bp (ver seccion 2.2).

Este cambio, a nivel de comunicacion, ha implicado una remodelacion de

todas las clases que se encargan de las funciones de red, ademas del fun-

cionamiento del aplanado y desplanado de las peticiones. El objetivo que

se propone para esta ultima fase es el de dar el soporte del protocolo Bp a

nuestro servicio.

4.4.1. Diseno del protocolo Bp

El paquete protagonista en este prototipo es, sin duda, el paquete net.

Hasta ahora tenıamos nuestro servicio funcionando bajo un nuestro sencillo

protocolo STRp, implementado en net.strp. En esta fase anadimos al paquete

net el subpaquete net.bp, que dara el soporte de red definitivo al servicio.

Algunos de los elementos mas importantes de este paquete son los objetos

que conforman el mensaje bp, el elemento basico del protocolo. Este mensaje

estara formado por una cabecera acompanada de una peticion al servicio y

mas tarde de una respuesta de este. Hay que tener en cuenta que no todos

las peticiones requieren respuesta. Las peticiones tendran un tamano maxi-

mo establecido por el buffer de conexion y, en el caso de necesitar enviar mas

CAPITULO 4. ARQUITECTURA Y DISENO 32

datos, se construyen mas mensajes de peticion y se mandan al servicio de

una forma continuada, una rafaga. La estructura de la cabecera es siempre

la misma, teniendo esta un ((numero magico)), un numero de secuencia y un

codigo de operacion. El resto del mensaje variara dependiendo del tipo de

operacion a realizar (se recomienda [4]).

Peticion Cuerpo Respuesta

Make nombre info info

Delete nombre

Get nombre offset lon buffer

Put nombre offset lon buffer

List nombre lon string

Info nombre info

Chinfo nombre info

Otro elemento que cabe destacar en este paquete es la conexion (ver figu-

ra 4.9). Se creara una conexion para recibir a cada peticion nueva y es en la

conexion donde se realiza la labor de desempaquetado y primer procesamien-

to de la peticion. Cada conexion guarda una referencia al sistema de cajas y

es con ella con la que invocamos los metodos pertinentes para la gestion de

los widgets.

Figura 4.9: Dos conexiones atienden a dos peticiones de sendos usuarios

CAPITULO 4. ARQUITECTURA Y DISENO 33

4.4.2. Cajas de proposito especifico: /mouse, /keyboard

y /clipboard

En esta version se han incorporado tambien varias cajas que se pueden

denominar de proposito especıfico, que se crean cuando se inicia el servicio:

son /clipboard, /keyboard y /mouse. La caja /mouse tiene como funcion servir

de recibidor a eventos de raton. Estos eventos se lanzan contra la caja real-

izando puts sobre ella y, de esta manera, conseguimos un control total sobre

el puntero del raton de cualquier sistema grafico que tenga arrancado nuestro

servidor.

put /b/ui/mouse 1:150:50

De esta manera conseguimos una pulsacion del boton 1 del raton, sobre

la coordenadas x=150 e y=50. La peticion es empaquetada en un buffer de

bytes como una peticion de escritura normal. Cuando el servidor la recibe y

la procesa, actualiza el contenido de la caja /mouse y genera el movimiento

de raton pertinenete en el dispositivo de visualizacion de la maquina donde

este arrancado. Este ejemplo se ilustra en la figura 4.10. Todo comienza con

el envio de una peticion de actualizacion de /mouse (1). El servidor recibe y

procesa esta peticion, actualizando primero la caja /mouse (2) y luego mane-

jando las librerıas graficas sobre las que funciona, para modificar la posicion

del cursor (3).

Figura 4.10: Funcionamiento de /mouse

CAPITULO 4. ARQUITECTURA Y DISENO 34

La caja /keyboard tiene un funcionamiento muy similar con relacion al

teclado. Sobre ella realizaremos puts que contengan el caracter que deseamos

presionar y, de este modo, tendremos el control sobre un teclado ((virtual)) en

nuestro servidor.

put /b/ui/keyboard s

Con este mensaje pulsariamos la tecla ’s’. El funcionamiento es similar al

de una peticion sobre /mouse.

La caja /clipboard cumple la funcion de un portapapeles clasico. Cuando

realizamos una operacion de copiado de un texto, seleccionandolo, este se al-

macena en /clipboard a la espera de que se realize una operacion de pegado.

El contenido de esta caja es accesible como el de cualquier otra. Ası un get

/clipboard nos devolverıa el contenido del portapapeles y una operacion co-

mo put /clipboard ((contenido)) actualizarıa el contenido de este. La siguiente

ilustracion muestra la relacion entre la caja /clipboard y el clipboard propio

del sistema grafico nativo.

Figura 4.11: Funcionamiento de la caja clipboard bajo una peticion de put

En la figura 4.11 se puede ver el proceso de actualizacion de /clipboard.

Todo comienza con la peticion de escritura en /clipboard del mensaje ((Hola

mundo))(1). Nuestro servicio procesa la peticion, no solo actualizando el con-

tenido de la caja /clipboard (2), sino tambien actualizando el buffer de sistema

CAPITULO 4. ARQUITECTURA Y DISENO 35

que desempene la funcion del portapapeles (3). Cuando decimos sistema nos

referimos al sistema grafico sobre el cual esta arrancado nuestro servicio.

Ahora tenemos este buffer del sistema sincronizado con nuestra caja /clip-

board. Si otro usuario del servicio realiza una operacion de pegado sobre un

widget (4), trasladara el contenido del buffer del sistema grafico y por ende

de /clipboard a dicho widget.

Capıtulo 5

Implementacion

En este capıtulo se aborda la implementacion de los elementos descritos

en el capıtulo anterior, correspondiente a la arquitectura.

5.1. Introduccion

Con los requisitos y la arquitectura general ya explicada, abordaremos

a continuacion todos los detalles de la implementacion de los diferentes pa-

quetes de nuestro servicio. Comenzaremos senalando que la totalidad del

servidor esta implementada usando java[7]. La aplicacion cliente, por contra,

se ha realizado usando C (ver seccion 2.2). Antes de comenzar a explicar a

fondo la implementacion del servicio, se recomienda que para cualquier duda

sobre la sintaxis o uso de alguna clase se recurra la documentacion de la API

del servicio[9].

5.2. Prototipo 1: Servidor de widgets

El desarrollo del servicio comienza centrado alrededor de un objeto, la

caja. Antes incluso de preparar un soporte sencillo de comunicaciones, debe-

mos crear la estructura adecuada tanto para la caja como para almacenar

esta. La caja, en cuanto a funcionalidad, es el resultado de la especializacion

de varias clases heredadas; en un comienzo se ha elaborado una clase basica

(box) que contiene exclusivamente la interfaz exigida por los requisitos de

Plan B (ver [3] o seccion 1.4), mas tarde, otra clase (serverBox), que anadıa

36

CAPITULO 5. IMPLEMENTACION 37

la funcionalidad necesaria para el uso de esta dentro del servicio, heredo de

la primera. Por ultimo, se llega a los widgets; estas clases se basan en las

anteriores y anaden al estado de sus predecesoras lo necesario para cada tipo

de widget en cada caso. Como se necesitaba generalizar el acceso y creacion

a cada widget, sin perder la funcionalidad, se creo una familia de interfaces

que evoluciono paralela a las tres clases anteriores. Tenıamos al final, la in-

terfaz widgetStruct que apoyaba el manejo de los objetos widgets. Podemos

ver esta relacion de clases en la figura 5.1.

Con la caja ya creada, ahora queda almacenarla; necesitamos un almacen

que entre otras caracterısticas sea redimensionable y de rapido acceso. Se

creo entonces la clase systemBox. Esta clase puede verse como el autentico

nucleo de todo el servidor. El objeto systemBox se crea durante el arranque

del servicio y la gran mayorıa de los objetos que se crearan a continuacion

(cajas, conexiones, escuchadores, etc) guardan una referencia suya. Esta clase

parte de un array de objetos de tipo widgetStruct. Cada caja tiene asociado

un ındice o posicion que ocupa en este array. Este ındice no variara durante

la vida de la caja.

Figura 5.1: Esquema de la familia de clases para que conforman la caja

CAPITULO 5. IMPLEMENTACION 38

5.2.1. La Caja

La caja es la idea basica en la que se centra nuestro servidor. Como se ha

dicho antes, la caja es el resultado de la evolucion de un grupo de clases e

interfaces. Partimos nuestro desarrollo de la clase box, que implementa la in-

terfaz mas basica del arbol arriba expuesto, la interfaz boxStruct. Esta clase

almacena el estado completo de la caja. El motivo de que las clases heredadas

de esta no anadieran ningun atributo al estado fue la claridad del codigo y

facilidad de depuracion. A continuacion mostramos su estado y sus metodos

mas importantes:

class box implements boxStruct{protected String name; //nombre de la caja

protected byte buf[]; //buffer donde almacenamos el contenido

protected int len; //tama~no de este contenido

protected info infob; //puntero a una estructura info

protected systemBox sysRef; //referencia al sistema de cajas que la contiene

protected indexTable itable; //tabla de ındices de las cajas que contiene

void put(byte[] newData);

public byte []get();

public String list();

public void copy();

public void setInfo(info i);

public info getInfo();

}

La estructura info esta presente en cualquier caja y recoge una coleccion

de metadatos asociados a esta (propietario, fecha de creacion, fecha de modi-

ficacion, permisos, etc). Otro atributo importante de esta clase es la iTable o

tabla de ındices. Esta tabla almacena los ındices (ver apartado 5.2) de cada

caja que se ha creado en su interior. Esta clase box implementa la funcionali-

dad mas basica y esencial de la caja. La implementacion del servicio requerıa

una interfaz de caja algo mas completa, por lo que se decidio refinar la abs-

traccion un nivel mas. Aquı se muestra la clase serverBox que hereda de la

anterior e implementa su correspondiente interfaz.

class serverBox extends box implements serverBoxStruct{

CAPITULO 5. IMPLEMENTACION 39

public void putBox(int index); //inserta un ındice en su iTable

public void delBox(int index); //borra un ındice de su iTable

public String getName(); //nos devuelve el nombre de la caja

public int getSize(); //devuelve el tama~no de la caja

public indexTable getBoxInto(); //devuelve un puntero a la iTable de la caja

}

Aun necesitamos mostrar en pantalla, de alguna manera, estas cajas; por

lo tanto se hace necesario otro nivel mas de refinamiento que de lugar a atri-

butos de visualizacion. De la anterior clase heredan todas las clases widgets.

Cada una de las clases widgets es diferente a sus hermanas, aunque para

todas se ha seguido un mismo convenio de nombrado: La letra W seguido del

widget que visualizan (Wrow, Wbutton, Wradio, etc). Para dar una gene-

ralidad de acceso y manejo a todas estas clases hermanas se ha usado una

interfaz que implementan todas ellas: widgetStruct. A continuacion se mues-

tran los metodos mas importantes de esta interfaz.

interface widgetStruct{public byte getType(); //Devuelve el codigo con el tipo de widget

public void InsertarAWT(Component c); //inserta un objeto AWT

public void RemplazarAWT(Component c); //Remplaza un objeto AWT

public void DestruirAWT(String c); //borra un objeto AWT

public void DestruirAWT(); //borra todos los componentes AWT

public void updateControl(boolean up);

}

A pesar de sus diferencias todas las clases widgets poseen un estado simi-

lar con dos atributos basicos que han sido anadidos al estado general, hereda-

do de la clase box anteriormente explicada. El primero de ellos es un puntero

a un componente AWT, que representara a la caja en el dispositivo de vi-

sualizacion y cambiara segun el tipo de widget. Por ejemplo, las clases Wrow

y Wcol usan el mismo objeto llamado java.awt.Panel. El segundo atributo

comun a todas las clases widgets es un codigo de tipo; en el almacenamos

un codigo que describe el tipo de clase que lo contiene. Los metodos que cita

esta interfaz cumplen la funcion de relacionar la caja con el objeto AWT que

alberga. Describimos estos metodos a continuacion:

CAPITULO 5. IMPLEMENTACION 40

InsertarAWT

Inserta un objeto AWT dentro del objeto AWT de la caja que lo invoca.

RemplazarAWT

Remplaza uno de los objetos AWT contenidos en nuestra referencia

AWT.

DestruirAWT

Destruye un objeto AWT contenido en nuestro objeto AWT.

updateControl

Este metodo se encarga de sincronizar el contenido de la caja con su

representacion grafica. De esta manera cuando un widget sufre un cam-

bio por parte del usuario de la interfaz, es este metodo quien actualiza

el contenido de la propia caja. Por otro lado la caja es actualizada

o escrita a traves de un put; el metodo updateControl() actualiza la

representacion grafica del objeto AWT contenido en la caja.

Las clases widget se explican a continuacion, aunque para una compren-

sion total de las clases propias de Java mencionadas se recomienda apoyarse

en las referencias citadas en la bibliografıa [8, 7]. Comenzaremos detallan-

do las caracterısticas de las clases widgets que pertenecen al subgrupo de

componentes.

Wbutton

Dibuja un boton en la pantalla. Esta clase contiene una referencia a

un objeto Button de AWT. Este puede encontrarse solo en dos esta-

dos: presionado o liberado; de ahı que su contenido se resume en un

solo caracter: p para el caso de que el boton se encuentre presionado

y r cuando el boton este en estado inactivo. Este widget puede emitir

dos tipos de eventos, el tipo 1 cuando el boton sea pulsado y el tipo 0

cuando sea liberado.

Wradio

Este widget es un caso atıpico. Solo puede ser creado dentro de un

contenedor de tipo menu. Su estado y eventos son similares a los del

button, siendo igual en todos los sentidos al primero. A este widget se

le adosa durante su construccion el escuchador Lradio.

CAPITULO 5. IMPLEMENTACION 41

Wcheck

El widget check funciona de forma muy similar al anterior. Como

diferencia tenemos que, cuando hay varios checks dentro de un mis-

mo menu solo uno de ellos puede estar en estado de ((pressed)) en cada

momento. Cuando un check es pulsado los demas de su menu seran li-

berados automaticamente. A este objeto se le adosa durante su creacion

un escuchador de tipo Lcheck.

Wentry

Representa una entrada de texto. El objeto AWT usado para darle su

apoyo grafico es TextArea. Este widget contiene el texto que se ha es-

crito sobre el area editable. Cada vez que el texto cambie, el widget

entry notificara un evento que contenga su ultimo contenido. Aquı se

puede observar lo anteriormente comentado sobre el metodo update-

Control(), ya que en este caso es crucial que el contenido de la caja sea

siempre el mismo que el mostrado a traves del objeto TextArea.

Wgauge

Dibuja una barra deslizante, con un valor de entre 1 y 100. Para repre-

sentar este widget se uso el objeto slider del paquete AWT. Este widget

contiene en su interior el valor actual de la barra. A efectos de eventos se

comporta de forma similar a entry, provocando un evento, cada vez que

el valor es modificado y notificando este nuevo valor en el propio evento.

Wlabel

El widget label sirve para escribir texto en una interfaz que no permita

ser editado. Para este widget se uso el objeto label de la librerıa AWT.

El widget label contiene el texto que muestra por pantalla. Inicialmente

se visualiza como texto el nombre del widget hasta que este es actual-

izado por medio de puts.

Wimage

El widget image se usa para poder cargar imagenes dentro de una inter-

faz. Contiene un puntero a un objeto Panel de AWT. Sera en este Panel

donde se carge el objeto image de AWT que contiene la representacion

CAPITULO 5. IMPLEMENTACION 42

grafica de archivo tipo gif o jpeg. Este widget no escucha eventos. Es

similar a un widget label pero con contenido grafico; de ahı que guarde

en su interior los bytes del archivo grafico.

Wrectangule

El widget rectangule funciona de forma similar al anterior aunque con

la diferencia de que sı transimite eventos.

Los widgets contenedores son tres, row, col y menu. Recordamos que estos

widgets carecen de una implementacion del metodo updateControl, pues no

hay ningun contenido que sincronizar. Ademas nunca se les adosara ningun

escuchador. Por contra estos widgets seran los unicos que implementen los

metodos InsertarAWT, RemplazarAWT y DestruirAWT()en sus dos ver-

siones, a diferencia de los antes explicados que no implementaban estos meto-

dos, ya que los objetos AWT que contenıan no podıan contener a su vez otros

componentes AWT.

Wrow

La caracterıstica diferenciadora de este contenedor reside en la vi-

sualizacion en pantalla de los widgets que contiene. Debido al layout[8]

usado por este objeto, muestra los widgets contenidos de izquierda a

derecha segun se van anadiendo al contenedor. Para dotar a este widget

de contexto grafico se ha usado el objeto Panel de AWT.

Wcol

Este contenedor funciona de forma similar al anterior. Usa un layout

diferente y de ahi que muestre sus componentes de arriba a abajo.

Wmenu

Para el widget menu se ha usado una implementacion similar a la de

widget col. Usa una referencia a un objeto Panel, donde a la creacion

de este le inserta un objeto label de AWT. De esta manera, dibujamos

un menu que mostrara sus opciones en columna y que, en su parte su-

perior, mostara un texto con el nombre del menu.

CAPITULO 5. IMPLEMENTACION 43

5.2.2. El sistema de cajas

El sistema de cajas es una gran tabla que almacena las referencias a todas

las cajas que creemos en nuestro servicio. El estado de la clase systemBox se

muestra a continuacion:

class systemBox{private widgetStruct btable[]; //array con las referencias a las cajas

private int nbox; //numero de cajas almacenadas

private int nMaxBox; //numero maximo que puede almacenar

}

Como se puede observar por el estado de la clase, nuestro sistema de ca-

jas es aun muy simple en este primer prototipo. La interfaz del sistema es

igualmente simple: una operacion de insercion, una de borrado y metodos

que devuelven una referencia a una caja dado su nombre o su ındice. Cabe

decir que desde este primer prototipo el sistema de cajas posee una operacion

privada de redimensionado, para evitar ası que limitar el numero de cajas

que puede albergar. Pasamos a explicar los metodos mas importantes del

sistema de cajas:

Cuando la conexion recibe una peticion de tipo make, invocara el metodo

addbox. La funcion de este es la creacion de un objeto caja y la insercion de

este en el sistema. El metodo primero crea una instancia de un objeto widget

concreto y lo iguala a una referencia widgetStruct; el tipo de este se sabe

gracias al nombre de la caja a crear (ver seccion 3.2 y manual de ui en [4]).

Tras esto, se crea el objeto AWT que encaje en este widget, se introduce el

objeto AWT en la caja widget para al final introducir esta en el sistema.

La funcion de borrado de una caja viene implementada en el metodo

deletebox. Este metodo debe asegurarse que dado un nombre de la caja a

borrar, esta debe ser sacada del sistema de cajas junto con las cajas que con-

tiene y todas ellas eliminadas. Si la caja es un componente entonces es simple,

se la elimina del sistema, se elimina su ındice de la iTable de su contenedor

y borramos del objeto AWT del contenedor el objeto AWT de la caja que

estamos borrando. Si la caja es un contenedor resulta mas complicado pues

puede contener mas cajas donde estas pueden ser igualmente contenedores.

CAPITULO 5. IMPLEMENTACION 44

Para ello recurrimos a un algoritmo recursivo, implementado como metodo

privado que exponemos a continuacion.

public void deleteBox(caja){widgetStruct padre;

si isComponent(caja)

cleanComponent(padre,caja)

si no

cleanContainer(padre,caja);

}

Donde el metodo cleanContainer se ha implementado siguiendo este pseu-

docodigo:

private void cleanContainer(widgetStruct padre,caja){padre.DestruirAWT(caja.nombre); //borra del AWT del contenedor el AWT hijo

indexTable hijos=caja.getBoxInto();

mientras (hijos[i]) //eliminamos nuestros hijos

si isComponent(hijo[i])

btable[indiceDeCaja]=null;

si no

cleanContainer (this,hijo[i]);

cleanComponent(padre,this); //nos borra de nuestro padre.

}

5.3. Prototipo 2: Servidor de widgets y

eventos

Como ya se explico en el apartado de diseno (ver seccion 4.3) este pro-

totipo implementa sobre su version anterior el sistema de recogida y gestion

de eventos. En la implementacion de este mecanismo han sido modificadas

las clases widgets y el sistema de cajas entre otros. Este sistema se basa en

un modelo de propagacion, donde cada caja que recibe un evento de alguna

de sus cajas contenidas intentara entregarlo o lo pasara a su caja contenedor.

CAPITULO 5. IMPLEMENTACION 45

5.3.1. Los escuchadores

Un escuchador es un tipo de objeto fundamental dentro del sistema de

eventos. Cuando creamos un widget componente le adosamos un objeto es-

cuchador. La funcion de este objeto sera la de activar el mecanismo de paso

de mensajes, cuando se produzca el evento sobre el widget que lo contiene.

Por ejemplo, cuando se instancia un widget de tipo boton (Wbutton) le

adosamos un objeto instanciado de la clase Lbutton (las clases escuchadores

se han nombrado con el caracter ’L’ seguido del nombre del widget para el que

trabajan). Este escuchador detectara cuando se ha presionado sobre el objeto

boton que lo contiene, creara un mensaje de evento y se lo enviara al con-

tenedor del boton (figura 5.2). Como se explicara a continuacion, podremos

tener conexiones dormidas a causa de peticiones de eventos inacabadas. Cada

vez que un escuchador detecta un evento, ademas de la notificacion de este,

despertara a las conexiones dormidas para que estas puedan comprobar si

pueden hacerse cargo de dicho evento.

Figura 5.2: Widget de tipo boton con un escuchador adosado

5.3.2. Notificacion y recoleccion de eventos

La notificacion es el proceso por el cual cada widget envıa un mensaje

de evento a la caja que lo contiene. Cuando se produce un evento en un

componente, el contenedor que lo contiene recibira este mensaje de evento.

El contenedor comprueba si hay una peticion de eventos en curso dirigida a

el o a alguno de sus contenidos. En caso negativo notificara el evento a su

contenedor para que este haga lo mismo. Puede darse el caso de que no haya

CAPITULO 5. IMPLEMENTACION 46

nadie interesado en este evento y se haya notificado al contenedor raız; en ese

caso, el proceso de notificacion devolvera un resultado negativo por el cual

el evento sera acolado en el contendor del componente que sufrio el evento.

El algoritmo de notificacion para un componente es simple:

boolean eventNotify(eventMsg msg){widgetStruct padre;

padre.eventNotify(msg); //el evento se traslada directamente a nuestro contenedor

}

Para el caso de un contenedor, el algoritmo se complica levemente:

boolean eventNotify(eventMsg msg){widgetStruct padre;

si (peticionActual!= ((get /events/miNombre)))

si padre.eventNotify(msg)==false //el evento no se ha entregado

encolo(msg);

return false; //no he podido entregar el evento

si no //el evento se ha entregado.

return true;

si no //el evento interesa y se acola hasta que se recolecte; entregado

encolo(msg);

return true;

return false;

}

Cuando alguien realiza una peticion de eventos sobre un contenedor, lo

primero es recolectar todos los eventos acolados en este y en los contenedores

alojados bajo el. Para ello se realiza una operacion de recoleccion. Es una

operacion muy sencilla: tan solo hemos de ir hijo a hijo recogiendo el con-

tenido de sus colas en un buffer y que estos hagan lo mismo con sus hijos.

Cuando la llamada inicial concluye, tenemos un buffer con todos los eventos

ocurridos bajo el contenedor que se realizo la peticion. Este buffer pasara a

la conexion para ser devuelto al peticionario.

La figura 5.3 muestra este proceso. Tras una peticion de eventos al con-

tenedor /row:f (1), este recolecta los eventos de sus hijos (2). Cuando tiene

CAPITULO 5. IMPLEMENTACION 47

todos estos eventos almacenados, el servicio la envia al peticionario a traves

de la conexion (3).

Figura 5.3: Proceso de recoleccion de eventos

Estos dos metodos se han anadido a la interfaz widgetStruct en esta

version del servicio; de esta manera todas las clases widgets, que son las

que implementan esta interfaz (ver seccion 5.2.1) pueden ejecutar estos dos

mecanismos. Ademas, en este prototipo se ha dotado a todos los contene-

dores de una cola donde poder almacenar los eventos no entregados de sus

componentes.

5.3.3. La caja /events

Esta caja es creada durante el arranque del servicio y funciona como in-

terfaz de manejo de eventos entre el usuario y el servicio. Esta caja mantiene

un subarbol de cajas similar al principal, de tal forma que, si encontramos

una caja con un nombre /a, seguro que existe otra caja llamada /events/a.

Cuando realizamos una peticion de eventos sobre una caja nos seran devuel-

tos todos los eventos que han involucrado a esta caja y a todas las interiores a

ella. Si no se han producido eventos que afecten a la caja pedida la conexion

que maneja esa peticion quedara bloqueada, a la espera de estos. Cuando

realizamos una peticion de eventos (get /events/unContenedor) arrancamos

un proceso de recoleccion de eventos, que se explico en el apartado anterior,

sobre ese contenedor.

CAPITULO 5. IMPLEMENTACION 48

Cada vez que un escuchador notifica un mensaje de eventos despierta a to-

das las conexiones que estan dormidas y que previamente, antes de dormirse,

se encolaron en un cola de conexiones. Cada conexion comprueba si hay even-

tos que puede servir y, en caso negativo, volvera a dormirse a la espera de

que otro escuchador la despierte. Es la propia conexion quien controla esto

cuando alguien hace una peticion de eventos. El algoritmo de este mecanismo

se resume aquı en pseudocodigo:

widgetStruct contenedor; //caja contenedor sobre la que pedimos sus eventos

for (;;){bufferEventos=contenedor.recolectaEventos();

si (bufferEventos==NULL)

colaConexiones.putConexion(this); //nos encolamos en la cola de conexiones

wait();

si no

return bufferEventos;

}

5.4. Prototipo 3: Servidor de widgets y

eventos sobre Bp

Llegados a este punto, tenemos totalmente implementado un servicio fun-

cional como el descrito en las especificicaciones. A pesar de eso para dar so-

porte grafico a Plan B con dicho servidor, este debe entender el protocolo

propio de este sistema distribuido, el protocolo Bp (ver seccion 1.4.1). El

paquete net es el encargado de soportar las distintas implementaciones de

protocolos que ((habla)) nuestro servicio y, por ello, el protocolo Bp se imple-

mento en el subpaquete net.bp.

5.4.1. Implementacion del protocolo Bp

Para dar soporte a este protocolo se han necesitado entre otros dos ob-

jetos fundamentales: el objeto peticion y el objeto respuesta. El primero se

instancia al desempaquetar un buffer de bytes enviado desde el cliente. Una

CAPITULO 5. IMPLEMENTACION 49

vez que tenemos el objeto peticion creado, este es procesado, obteniendose

un objeto respuesta que sera convertido en un buffer de bytes (aplanado)

y enviado de vuelta al cliente. Esto ultimo solamente en los casos en que

la peticion requiera una respuesta (ver apartado de requisitos 3.2). A con-

tinuacion se muestra la implementacion del objeto peticion:

public class petition{public bpHeader hdr; //estructura de cabecera

private String usr; //peticionario

private String auth; //autentificacion

private String saddr; //direccion del peticionario

public String box; //nombre de la caja

public BigInteger lcount; //list

public info infob; // make, chinfo

public BigInteger serial0; //get, put

public BigInteger off; //get, put

public BigInteger count; //get, put

public byte[] data; //put

...

}El objeto respuesta se crea con la misma cabecera que la peticion que le

precede y con un cuerpo que, igual que en la peticion variara segun sea una

operacion u otra.

public class reply{public bpHeader hdr; //misma cabecera que su peticion

public String rstr; //list

public BigInteger rcount; // get

public byte[] rdata; // get

public info rinfo; // info, make

...

}

Por ultimo mostramos la estructura de cabecera: un ((numero magico)),

que asegura la valided de la peticion, un codigo de operacion y un numero

de secuencia. Este numero de secuencia tiene una funcion crıtica cuando se

establece una rafaga de peticiones (recordar apartado 4.4.1). En este esce-

CAPITULO 5. IMPLEMENTACION 50

nario el numero de serie del primer paquete de una rafaga se guarda en los

campos serial0 de cada peticion de la rafaga.

public class bpHeader{private BigInteger magic;

private BigInteger serial;

private BigInteger op;

...

}

5.4.2. Implementacion de la conexion

Tenemos en este paquete un elemento basico: la conexion. Esta ha sido

implementada como un objeto instanciable en un hilo independiente, recibe

una buffer de bytes que desempaqueta y procesa. Esta clase conexion posee

un metodo por cada tipo de peticion que debe procesar. Obtiene una respues-

ta que es empaquetada y devuelta al cliente. El algoritmo serıa similar a este:

petition pet;

reply res;

byte []buffer;

buffer=recivimosPeticion();

pet.unpack(buffer);

switch (pet.getOperation()){put:

Put (pet);

get:

res=Get(pet);

make:

res=Make(pet);

del:

Delete(pet);

......

}buffer=res.pack();

enviarRespuesta(res);

Como se puede apreciar en el anterior pseudocodigo, no todas las peti-

ciones implican una respuesta, ası un mensaje de put o del por ejemplo no

devuelven ningun mensaje al peticionario. Cada peticion serıa atendida por

CAPITULO 5. IMPLEMENTACION 51

una conexion diferente que se cerrara una vez procesada enteramente. Para

un procesamiento total de la peticion, la conexion debe interactuar con los

demas paquetes del servicio. El siguiente paso al desempaquetado de la peti-

cion es la invocacion de metodos del sistema de cajas (ver systemBox; seccion

5.2.2).

Por ejemplo tenemos una peticion como la siguiente:

make /b/ui/row:fila

Esta peticion esta ordenando la creacion de una caja con el widget row.

La peticion sera desempaquetada y tratada por el algoritmo antes explicado.

Cuando tenemos un objeto peticion, vemos cual es el codigo de operacion

y ejecutamos el metodo privado de la conexion adecuado, en este caso, el

metodo Make.

Figura 5.4: Dos conexiones, arrancadas en distintos threads, atienden sendas

peticiones

Debido a que la conexion guarda una referencia al sistema de cajas crea-

do al inicio del servicio, esta puede, tras realizar algunas comprobaciones

(permisos, propietario, etc) invocar desde su metodo Make al metodo addbox

del sistema de cajas y crear ası la caja en el propio sistema. La figura 5.4,

CAPITULO 5. IMPLEMENTACION 52

muestra la relacion entre el paquete net con el objeto conexion y los demas

paquetes del servicio.

A continuacion se exponen los metodos de la clase conexion usando no-

tacion en pseudocodigo. Comenzamos exponiendo el metodo Make, antes

analizado.

private reply Make(petition req){si es peticion incorrecta

error

widgetStruct padre

si padre.getInfo().operacionPermitida("make")==false

error

sistema.addbox(req.box)

widgetStruct cajaCreada.setInfo(req.info)

reply rep

}

El metodo Delete se ha implementado, siguiendo una interaccion con el

systemBox similar a del anterior metodo.

private void Delete(petition req){widgetStruct padre

si padre.getInfo().operacionPermitida("delete")==false

error

sistema.deletebox(req.box)

}

Los metodos Get y Put tienen algo mas de complejidad, pues diferencian

si la peticion esta dirigida hacia una de las cajas de proposito especıfico o a

un widget general. Ademas, el metodo put comprueba si la peticion pertenece

a una rafaga (recordar seccion 4.4.1); en ese caso concatenara el contenido

llegado en el mensaje al que ya tenıamos en la caja. Si la peticion de put es

unica, coloca los bytes en la caja.

private reply Get(petition req){si (req.box==/events)

CAPITULO 5. IMPLEMENTACION 53

getEvents() //recordar seccion 5.3.3

si (req.box==/clipboard)

return reply(getClipboardContent()) //accedemos al clipboard del sistema

si caja.getInfo().operacionPermitida("get")==false

error

return reply(caja.get())

}

private void Put(petition req){si (req.box==/events)

error

si (req.box==/clipboard)

return setClipboardContent(req.data) //accedemos al clipboard del sistema

si caja.getInfo().operacionPermitida("put")==false

error

si esRafaga(req)

caja.put(caja.get()+req.data)

si no

caja.put(req.data)

}

Las peticiones list,info y chinfo siguen estructuras similares a las anteri-

ores y con ellas se cierra el repertorio de peticiones que oferta el protocolo Bp.

5.4.3. Implementacion de /keyboard y /mouse

Como ya se ha explicado en el capitulo de arquitectura, en este prototipo

ademas de los cambios a nivel de red se introdujeron una serie de cajas que

cumplen funciones muy concretas. Estas dos cajas soportan las funciones

de un teclado y raton virtual. Para su desarrollo fue crucial el uso de una

clase ofrecida por la API de AWT, llamada Robot. Esta clase se encarga de

provocar movimientos de raton y pulsaciones de teclado de la misma manera

que si fueran hechos desde los propios perifericos. Ası, de esta manera, se

construyeron dos clases similares llamadas Dkeyboard y Dmouse, que im-

plementan la interfaz widgetStruct necesaria para estar dentro del sistema

de cajas (se uso el caracter ’D’ por la palabra inglesa device). En esta clase

CAPITULO 5. IMPLEMENTACION 54

se rescribio el metodo put() para dar uso a los metodos propios de la clase

Robot de AWT, antes comentada.

De esta manera se consiguio un control de estos dispositivos perifericos

tan comunes a traves de las peticiones de Bp.

5.4.4. Implementacion de /clipboard

Esta caja tambien se introdujo en este prototipo. Forma parte del grupo

de las anteriormente comentadas, cajas de funcion especıfica. Esta caja rep-

resenta al clasico portapapeles, tan util en otros entornos graficos. Cuando se

realiza una operacion de copiado, automaticamente ese contenido es situado

dentro de /clipboard. De la misma manera cuando realizamos una operacion

de pegado, es el contenido de esta caja el que pegamos. Ası pues, el fun-

cionamiento de la caja es el un portapapeles clasico, con la ventaja de que al

estar implementado en una caja podemos acceder a el a traves de peticiones

Bp como get o put.

Cuando realizamos peticiones get o put a la caja /clipboard, el propio

objeto conexion hace uso del objeto Clipboard, ofrecido desde la API de Java

para leer o modificar el contenido de este. Al igual que cuando detectamos

que se esta intentando copiar o pegar de un widget, el escuchador de este

invocara a estos mismos metodos para la modificacion o acceso a este recurso

del sistema.

Capıtulo 6

Validacion y pruebas

Tras la fase de implementacion, cada prototipo necesita ser validado para

comprobar que cumple las especificaciones y que su funcionamiento es ro-

busto. Hemos explicado en este capıtulo a modo de ejemplo algunas de las

pruebas realizadas a cada prototipo, a fin de que ademas con ello se vea el

funcionamiento real del servidor.

6.1. Introduccion

Todas las pruebas se han realizado usando el shell desarrollado para la

depuracion del proyecto. Para las pruebas de los dos primeros prototipos,

este shell ha usado el protocolo STRp para la comunicacion con el servi-

cio. El tercer prototipo ya se comunicaba con el shell a traves de Bp. Se ha

documentado una prueba por prototipo a fin de extenderse demasiado, pero

se han realizado muchas mas para verificar todos los casos de prueba. A la

conclusion de este periodo de pruebas el servicio ofrece un funcionamiento

completo en relacion a la especificacion planteada al comienzo. En la figura

6.1 se puede ver una de las interfaces graficas generadas en una de las pruebas.

6.2. Prototipo 1: Servidor de widgets

Como ya se ha explicado, este prototipo se encarga de recibir peticiones

que ordenen la creacion, el borrado y la gestion del contenido de widgets.

Mostraremos el resultado de las pruebas realizadas a este prototipo. Lo

55

CAPITULO 6. VALIDACION Y PRUEBAS 56

Figura 6.1: Ejemplo de una interfaz grafica de usuario generada con nuestro

servicio

primero de todo obviamente es arrancar el servicio en las maquinas donde

queramos visualizar nuestra interfaz. Tras esto usaremos el shell de prueba

para enviarle las peticiones STRp (hay que recordar que este primer pro-

totipo aun no soporta el protocolo Bp; ver seccion 4.2).

Comenzamos creando un primer contenedor para a partir de el generar

una interfaz grafica sencilla:

[STRP]>make /col:prueba

Automaticamente se genera un marco sobre el que albergar mas widgets,

sobre el dispositivo controlado por el servicio (ver figura 6.2).

Tras esto creamos dentro de esta columna, una caja de texto editable (en-

try) y un boton (button), quedando el aspecto visual tal y como lo muestra

la figura 6.3:

[STRP]>make /col:prueba/entry:txt

CAPITULO 6. VALIDACION Y PRUEBAS 57

Figura 6.2: Marco recien creado

Figura 6.3: Marco tras crear el boton y la entrada de texto

CAPITULO 6. VALIDACION Y PRUEBAS 58

[STRP]>make /col:prueba/button:aceptar

Para asegurarnos que todo esta en su sitio listamos el contenido de los

widgets creados:

[STRP]>list /

/col:prueba

[STRP]>list /col:prueba

/col:prueba/entry:txt

/col:prueba/button:aceptar

Ahora pasamos a editar el widget entry. Antes de nada comprobamos el

contenido de esta, por si el usuario de la interfaz ha escrito algo.

[STRP]>get /col:prueba/entry:txt

[STRP]>

El contenido devuelto esta vacıo, por lo que el usuario aun no ha hecho

uso de la entrada de texto.

[STRP]>put /col:prueba/entry:txt "Escribe algo, por favor!!"

Si nos fijamos en el estado de la entrada de texto en nuestra interfaz (figu-

ra 6.4), veremos que esta ha cambiado mostrando el mensaje que contiene su

caja.

6.3. Prototipo 2: Servidor de widgets y

eventos

Tras implementar y comprobar el buen funcionamiento del primer pro-

totipo, se ha completado sobre este el desarrollo del segundo prototipo que

anade funcionalidad en la gestion de eventos. A continuacion se expondra una

de las pruebas llevadas a cabo para comprobar que el funcionamiento se ajus-

ta a la especificacion del diseno de esta version (recordar diseno, seccion 4.3).

CAPITULO 6. VALIDACION Y PRUEBAS 59

Figura 6.4: La entrada de texto, tras sincronizarse con su caja, muestra su con-

tenido

Al igual que con la version anterior comenzamos arrancando el servicio en

el dispositivo sobre el que queremos generar nuestra interfaz grafica. Una vez

hecho esto realizamos un primer listado a la caja raız para familiarizarnos

con el nuevo entorno.

[STRP]>list /

/events

[STRP]>

Como se puede ver, se ha creado una caja durante el arranque del servi-

dor. La caja /events se encarga de la entrega de los eventos ocurridos bajo

un contenedor concreto; esto ya se explico en capıtulos anteriores (ver sec-

cion 5.3.3). Procedemos con el inicio de la creacion, para ello comenzamos

generando una fila que contenga tres botones.

[STRP]>make /row:fila

[STRP]>make /row:fila/button:aceptar

CAPITULO 6. VALIDACION Y PRUEBAS 60

[STRP]>make /row:fila/button:cancelar

[STRP]>make /row:fila/button:salir

Ya tendrıamos una sencilla interfaz preparada para ser usada por el

usuario. Para poder atender sus peticiones a traves de la interfaz debemos

tener un control sobre los eventos que pueda desencadenar este sobre nuestra

interfaz. Para ello realizamos una peticion de eventos sobre el contenedor fila.

[STRP]>get /events/row:fila

Esta llamada es bloqueante, lo que provoca que la conexion permanecera blo-

queada hasta que se produzca un evento bajo el contendor /row:fila.

Como se aprecia en la figura 6.5, cuando el usuario de la interfaz grafica

pulsa uno de los botones, se genera un evento que es trasladado a nuestro

shell desbloqueando la conexion:

[STRP]>get /events/row:fila

/row:fila/button:aceptar#1#

[STRP]>

El mensaje devuelto nos da toda la informacion que necesitamos. Ahora

ya sabemos que el usuario ha interactuado con la caja /row:fila/button:aceptar

pulsandola (lo que se indica con el valor 1, el valor 0 indicarıa que el boton se

ha liberado). Si el usuario continuara manejando dicho boton u otro widget de

la interfaz, esos eventos irıan encolandose y serıan devueltos en una peticion

similar a la anterior.

6.4. Prototipo 3: Servidor de widgets y

eventos sobre Bp

El ultimo prototipo ya soporta el protocolo Bp, propio del sistema Plan

B. Este cambio fue transparente al resto de la aplicacion, por lo que la an-

terior funcionalidad continua siendo valida. Ademas de cara al usuario los

mandatos de STRp, usados en anteriores versiones, funcionan igual que sus

homologos de Bp. Para probar la correcta integracion de este protocolo en

CAPITULO 6. VALIDACION Y PRUEBAS 61

Figura 6.5: El usuario pulsa un boton produciendo un evento

nuestro servicio usaremos nuestro cliente-depurador bpsh, pero compilado

ahora con las librerıas ANSI-Bp, en lugar de con las del protocolo STRp y

realizaremos peticiones propias de este nuevo protocolo.

Al igual que sus predecesores, el servicio es arrancado para iniciar la

prueba. Enviamos una peticion de listado para comprobar los cambios de

esta nueva version.

[BP]>list /

/events

/clipboard

/mouse

/keyboard

[BP]>

Hemos comprobado el primer avance de esta nueva version con relacion

a la anterior. Como ya se comento en el capıtulos anteriores, durante el a-

rranque del servicio ahora se crean tambien las cajas /clipboard, /mouse y

/keyboard (ver seccion 4.4). Pasamos ahora a crear nuestra interfaz comen-

CAPITULO 6. VALIDACION Y PRUEBAS 62

zando por una fila inicial que contenga una entrada de texto.

[BP]>make /row:fila

[BP]>make /row:fila/entry:texto

Realizamos ahora una peticion para recuperar los metadatos de una de

las cajas:

[BP]>info /row:fila

cnstr:

owner: anonymous

putter:

vers: 0

size: 0

operm: 27

wperm: 17

[BP]>

Si hemos arrancado nuestro shell bpsh sin identificarnos, el usuario al que

se le asignan las cajas por defecto sera ((anonymous)). Esto es interesante a

la hora de la comprobacion de permisos. Intentaremos escribir en una caja

siendo otro usuario; para ello arrancamos otro bpsh identificandonos como

un usuario concreto:

[sdemingi@wagner:pruebas]>bpsh mozart sdemingi

[BP]>

En este momento hemos iniciado una comunicacion con el servicio arran-

cado en la maquina mozart identificados como sdemingi. Vamos a intentar

realizar una escritura en la caja /row:fila/entry:texto que es propiedad del

usuario anonymous desde el cliente arrancado a nombre de sdemingi.

[BP]>put /row:fila/entry:texto "escribo sin permiso??"

[BP]>

Comprobamos si la escritura ha tenido algun efecto (figura 6.6).

CAPITULO 6. VALIDACION Y PRUEBAS 63

Figura 6.6: La escritura no ha cambiado nada pues se carecıa de permiso para

actualizar el wiget

[BP]>get /row:fila/entry:texto

[BP]>

La funcion de actualizacion de contenido, segun los permisos establecidos

por defecto, solo le esta permitida al propietario de la caja y de ahı que no se

nos permita la escritura como usuario sdemingi. Obviamente estos permisos

se establecen durante la creacion de la caja y pueden ser modificados en to-

do momento gracias a la peticion chinfo (ver manual de PlanB [4]). Usamos

nuestro primer cliente, aquel que no tenıa ningun usuario identificado, para

enviar la misma peticion de escritura sobre la misma caja.

[BP]>put /row:fila/entry:texto "escribo sin permiso??"

[BP]>

Tras esto pedimos la informacion contenida en los metadatos para com-

probar que efectivamente la caja ha sido actualizada.

CAPITULO 6. VALIDACION Y PRUEBAS 64

[BP]>info /row:fila/entry:texto

cnstr:

owner: anonymous

putter: anonymous

vers: 1

size: 21

operm: 27

wperm: 17

[BP]>

[BP]>

[BP]>get /row:fila/entry:texto

escribo sin permiso??

[BP]>

Podemos ver que tanto el campo del ultimo modificador (putter), el

tamano de la caja (size) y la version de esta (vers) han sido actualizados.

Tras estas comprobaciones se ha validado el correcto funcionamiento de este

tercer prototipo del servicio, por lo que estamos en condiciones de afirmar

que disponemos de una version funcional y completa de nuestro servicio de

interfaces graficas para entornos distribuidos.

Capıtulo 7

Conclusiones

Con la totalidad del servicio probado se da por terminado el proyecto.

Terminaremos exponiendo las conclusiones a las que se ha llegado tras su

finalizacion. En este capıtulo se tratara de exponer a modo de conclusion un

resumen de los objetivos cumplidos, ası como de todo lo aprendido durante

la realizacion del proyecto.

7.1. Objetivos cumplidos

Se ha concluido el desarrollo del servicio de interfaces graficas. Este servi-

dor cumple la tarea fundamental de permitir la interaccion entre usuario y

sistema a traves de interfaces graficas situadas en multiples nodos del sis-

tema distribuido. Ademas del diseno y posterior implementacion, de una

aplicacion que se ajustara a los requisitos anteriormente expuestos (recordar

seccion 3.2), esta ha sido expuesta a numerosos casos de prueba que han

demostrado su validez y buen funcionamiento sobre distintas plataformas.

Para la realizacion de estas pruebas y para una depuracion correcta durante

el desarrollo, se ha construido un cliente-depurador capaz de comunicarse

con el servicio usando los protocolos STRp primero y Bp en las versiones

finales. Tras esto, el servicio se ha instalado en varias de las maquinas del

Laboratorio de Sistemas de la universidad, teniendo hasta el dıa de hoy el

funcionamiento deseado. A continuacion citamos de forma resumida todos

estos objetivos alcanzados:

65

CAPITULO 7. CONCLUSIONES 66

Diseno e implementacion de un servicio de interfaces graficas distribuidas.

Diseno e implementacion del cliente-depurador bpsh.

Creacion, manejo y control de una interfaz grafica distribuida, usando

el protocolo Bp y nuestro servicio.

Instalacion y prueba del servicio en varias plataformas como Linux 2.4

y Windows XP.

Instalacion de nuestro servicio en varias maquinas del laboratorio.

7.2. Lecciones aprendidas

El desarrollo de este proyecto ha supuesto un aumento en los conocimien-

tos relacionados con las plataformas y sistemas usados. La plataforma Java

ha estado presente durante todo el desarrollo del servicio. Esto ha ocasiona-

do un aprendizaje y una posterior profundizacion en este lenguaje y en sus

tecnologıas derivadas. De esta manera se ha obtenido un buen conocimiento

sobre comunicaciones, multihilado y programacion grafica bajo este lenguaje.

Ademas se ha conseguido un gran conocimiento de gran parte de la extensa

API que oferta java, mas en concreto, de su paquete AWT.

Cabe destacar que no solo ha sido Java el unico protagonista del desa-

rrollo. No hay que olvidar que el shell desarrollado para depurar y probar el

servicio ha sido desarrollado bajo C. Esto ha afianzado conocimientos basicos

sobre el lenguaje C y ha permitido ampliar estos a campos mas complejos del

lenguaje, como las comunicaciones gracias al manejo de la librerıa de sockets

de Linux.

Todo lo aprendido y leıdo sobre sistemas distribuidos ha sido de gran

ayuda, a la hora de abordar el desarrollo del proyecto y todos esos concep-

tos se han visto reforzados al finalizar nuestro servidor. En este campo cabe

destacar lo que sin duda ha sido el descubrimiento mas sorprendente, el sis-

tema Plan B y sus cajas.

En resumen y para concluir, se enumeran a continuacion las lecciones

aprendidas:

CAPITULO 7. CONCLUSIONES 67

Desarrollo de aplicaciones J2SE. Se destaca los paquetes de comunica-

ciones, threads y programacion grafica.

Programacion con la API de comunicaciones de GNU/Linux, necesaria

para el desarrollo del shell de prueba.

Funcionamiento interno del sistema operativo Plan B, su experimental

sistema de ficheros y el protocolo Bp.

Diseno de arquitecturas para servidores de ficheros.

Programacion de RPCs.

7.3. Valoracion personal

Como opinion personal y subjetiva de este proyecto, el balance a la con-

clusion de este, ha sido increıblemente positivo. Todo el desarrollo se ha

sucedido de una forma fluida y sin complicaciones dignas de mencion, aunque

cabe destacar que en la recta final se han sufrido demoras que han atrasado la

fecha de entrega. La comodidad y la tranquilidad con la que se ha afrontado

el diseno y desarrollo del servidor han sido claves para la correcta asimilacion

de todos los conceptos antes mencionados. Por todo esto, se ha de decir que

a pesar de haber finalizado este proyecto se quiere mantener la vinculacion

con el entorno de Plan B y del diseno de sistemas en general.

7.4. Trabajo futuro

La portabilidad ha sido uno de los puntos mas cuidados tanto en el diseno

como en la implementacion del servicio; por ello los analisis posteriores ha-

cen necesario una revision de algunas estructuras para mejorar aun mas esta

caracterıstica. Se han encontrado plataformas que, a pesar de ser compatibles

con Java, no pueden dar soporte a nuestro servidor (es el caso de Symbian).

El trabajo en futuras versiones del servicio tendra como punto central un

aumento de portabilidad. Para ello necesitaremos una revision del diseno a

fin de reducir la cohesion entre los tres modulos del servicio (recordar arqui-

tectura, capıtulo 4.1).

CAPITULO 7. CONCLUSIONES 68

Desde el punto de vista de la implementacion, se hace necesario una re-

vision en profundidad del paquete wdg. Esta revision debe tener como fin

una separacion mayor entre la estructura widget y el objeto usado para re-

presentarlo en pantalla, ya que actualmente ambos objetos estan ıntimamente

relacionados.

Con relacion al entorno natural de uso del servicio, el sistema Plan B, se

plantea como trabajo futuro, el desarrollo de servicios similares a este pero

dirigidos a tipos diferentes de cajas.

Bibliografıa

[1] Dan R.Olsen, Jr. Morgan Kaufmann publisher, inc, Design Human In-

terfaces.

[2] A.S. Tanembaum. Prentice Hall, Distributed System.

[3] F. J. Ballesteros and S. Arevalo, The Box: A Replacement for Files.

[4] http://www.lsub.org/ls/export/bman/index.html, Plan B User’s Man-

ual (2nd. ed.).

[5] A.S. Tanembaum. Prentice Hall, Operating System. Design and Imple-

mentation.

[6] S.Moritsugu. Serie Practica. Prentice Hall, Unix.

[7] A. Froute. Ra-Ma, Manual de usuario y tutorial de Java2.

[8] David M. Geary, Alan L. McClellan. SunSoft Press. Prentice Hall,

Graphic Java, Mastering the AWT.

[9] http://pantuflo.escet.urjc.es/sdemingi/pfcweb/index.html,Documentacion

de la API del servidor.

69