Post on 24-Jun-2020
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