• No se han encontrado resultados

Objetos Distribuidos en GNUstep

N/A
N/A
Protected

Academic year: 2021

Share "Objetos Distribuidos en GNUstep"

Copied!
18
0
0

Texto completo

(1)
(2)

Objetos Distribuidos en GNUstep

Nicola Pero

*

13 de enero de 2011

nicola.pero@meta-innovation.com

Primera edici´on: Enero 2002; ´Ultima actualizaci´on: Marzo 2010 Documento publicado bajo los t´erminos de la licencia GPLv3

1.

¿Que es la Distribuci´

on de Objetos (DO)?

En este tutorial introducimos al lector en el mundo de los Objetos Distribui-dos de GNUstep. Los Objetos DistribuiDistribui-dos son una colecci´on de facilidades que ofrece la librer´ıa Base de GNUstep que permite la comunicaci´on entre diferentes procesos corriendo en la misma maquina o en diferentes maquinas en la misma red. Los objetos distribuidos tambi´en pueden ser utilizados para la comunicaci´on entre diferentes hilos de la misma aplicaci´on.

La idea b´asica en los Objetos Distribuidos de GNUstep es una extensi´on normal de la programaci´on orientada a objetos que permite a los objetos, en diferentes procesos, llamar de forma transparente a los m´etodos de otros objetos. Los detalles de bajo nivel acerca de como este proceso de mensajes es hecho esta normalmente oculto dentro de el runtime GNU de Objective-C y dentro de la librer´ıa Base de GNUstep; esto le permite a usted concentrarse en el alto nivel de abstracci´on, dise˜nando una aplicaci´on distribuida como una composici´on de varios objetos corriendo en diferentes procesos. e intercomunicandose entre ellos usando mensajes. Los Objetos Distribuidos de GNUstep le proveen a usted con el soporte para dise˜nar aplicaciones de este tipo f´acil, limpia y r´apidamente. El c´odigo resultante es natural y entendible, lo que reduce el esfuerzo para mantener y extender una aplicaci´on distribuida.

En la practica, puesto que Objective-C soporta mensajes remotos, usted no necesita ninguna sintaxis especial o alguna herramienta de programaci´on adicional para mandar mensajes remotos - usted puede hacer esto con el mismo c´odigo que usa para mandar mensajes normales. Como consecuencia, los Objetos Distribuidos de GNUstep son muy simples y naturales de usar, y ellos caben f´acil y muy elegantemente en un framework orientado a objetos.

El nombre “Objetos Distribuidos de GNUstep” es generalmente abreviado GNUstep DO. En este documento seremos aun mas breves, y nos referiremos a ellos como DO.

(3)

2.

Un ejemplo b´

asico para mostrar archivos

Empezaremos con un programa b´asico que no utiliza DO - una herramienta de linea de comandos que acepta como argumento el nombre de un archivo, lee este archivo desde el disco, e imprime la salida a trav´es de stdout1. por ejemplo,

escribiendo:

Example C l i e n t .m

Una vez tengamos este ejemplo b´asico, en la siguiente secci´on extenderemos sus capacidades usando DO.

Nuestra herramienta b´asica es la siguiente: #i n c l u d e <Foundation / Foundation . h> /∗ E s t e o b j e t o t i e n e como t r a b a j o o b t e n e r un a r c h i v o d e l d i s c o duro ∗/ @ i n t e r f a c e F i l e R e a d e r : NSObject − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end @implementation F i l e R e a d e r − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e { r e t u r n [ N S S t r i n g s t r i n g W i t h C o n t e n t s O f F i l e : f i l e N a m e ] ; } @end i n t main ( v o i d ) { N S A u t o r e l e a s e P o o l ∗ p o o l ; NSArray ∗ a r g s ; i n t c o u n t ; F i l e R e a d e r ∗ r e a d e r ; N S S t r i n g ∗ f i l e n a m e ; N S S t r i n g ∗ f i l e ; p o o l = [ N S A u t o r e l e a s e P o o l new ] ; /∗ Creamos e l o b j e t o F i l e R e a d e r ∗/ r e a d e r = [ F i l e R e a d e r new ] ;

/∗ Obtenemos l o s argumentos d e l programa ∗/ a r g s = [ [ N S P r o c e s s I n f o p r o c e s s I n f o ] arguments ] ;

/∗ El p r i m e r s t r i n g en a r g s e s e l nombre d e l programa ;

(4)

nos i n t e r e s a e l segundo argumento , s i hay ∗/ i f ( [ a r g s c o u n t ] == 1 )

{

NSLog (@” E r r o r : debe e s p e c i f i c a r un nombre de a r c h i v o ” ) ; e x i t ( 1 ) ; } f i l e n a m e = [ a r g s o b j e c t A t I n d e x : 1 ] ; /∗ Pedimos a l o b j e t o l e c t o r que o b t e n g a e l a r c h i v o ∗/ f i l e = [ r e a d e r g e t F i l e : f i l e n a m e ] ; /∗ S i e l o b j e t o l e c t o r puede o b t e n e r e l a r c h i v o , m o s t r a r e s t e ∗/ i f ( f i l e != n i l ) { p r i n t f (” %s \n ” , [ f i l e l o s s y C S t r i n g ] ) ; } e l s e { NSLog (@” E r r o r : no s e puede l e e r e l a r c h i v o ‘ %@’ ” , f i l e n a m e ) ; e x i t ( 1 ) ; } r e t u r n 0 ; }

Para compilar este programa, necesitamos un GNUmakefile, como el sigu-iente:

i n c l u d e $ (GNUSTEP MAKEFILES) / common . make TOOL NAME = Example

Example OBJC FILES = example .m

i n c l u d e $ (GNUSTEP MAKEFILES) / t o o l . make

3.

Extendiendo el programa para manejar archivos

en la red

Ahora queremos modificar nuestro peque˜no programa para obtener archivos que est´en en otras maquinas de nuestra red, y desplegar estos en la maquina local.

Viendo otra vez en el c´odigo fuente de nuestro herramienta, vemos que ten-emos una funci´on main que analiza los argumentos de la linea de comandos, y que llama al m´etodo getFile: de nuestro objeto FileReader para leer el archivo

(5)

indicado; y entonces desplegar el contenido de este. Con la ayuda de un poco de magia, usted puede correr el objeto FileReader en una maquina remota, y la funci´on main en la maquina local, sin cambiar su c´odigo. La funci´on main debe analizar los argumentos de la linea de comandos, y entonces llamar al m´ eto-do getFile: del objeto FileReader (corrieneto-do en la maquina remota), el cual debe leer el archivo y retornar este a la funci´on main (que esta corriendo en la maquina local) como el valor de retorno del m´etodo getFile:; y por ´ultimo la funci´on main debe imprimir este.

Los Objetos Distribuidos de GNUstep le permiten a usted hacer esta clase de magia: llamar m´etodos de objetos remotos precisamente como si fueran objetos locales normales.

El dise˜no de nuestro ejemplo modificado sera un dise˜no cliente/servidor: tendremos un servidor, y un cliente. El servidor contendr´a el objeto FileReader ; y el cliente conectara con el servidor, para mandar el mensaje getFile: al objeto FileReader en el servidor, recibiendo en el retorno un string con el contenido del archivo.

4.

El servidor

El archivo Server.m contendr´a el c´odigo del servidor. B´asicamente, este con-siste de la clase FileReader mas una nueva funci´on main, la cual crea una in-stancia de FileReader y la ofrece a la red. Esto es, la expone a la red permitiendo que procesos remotos llamen a este a trav´es de los m´etodos GNUstep DO. Final-mente, el servidor pone al objeto FileReader en un ciclo de ejecuci´on esperando que algo suceda.

El c´odigo para ofrecer el objeto a la red es muy simple: primero se obtiene el objeto defaultConnection.

NSConnection ∗ conn = [ NSConnection d e f a u l t C o n n e c t i o n ] ; seguidamente le decimos a la conexi´on que objeto queremos ofrecer: [ conn s e t R o o t O b j e c t : r e a d e r ] ;

y finalmente, registramos esto en la red con un determinado nombre: i f ( ! [ conn r e g i s t e r N a m e :@” F i l e R e a d e r ” ] )

{

NSLog (@” I m p o s i b l e r e g i s t r a r n o s como F i l e R e a d e r ” ) ; e x i t ( 1 ) ;

}

el nombre es muy importante - el cliente necesita conocer el nombre del servidor para establecer una conexi´on con este y acceder al objeto ofrecido (que en este caso es el objeto FileReader ).

De esta forma, este es el c´odigo completo para el servidor: #i n c l u d e <Foundation / Foundation . h>

(6)

/∗ E s t e o b j e t o h a c e e l t r a b a j o de o b t e n e r un a r c h i v o d e l d i s c o duro ∗/ @ i n t e r f a c e F i l e R e a d e r : NSObject − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end @implementation F i l e R e a d e r − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e { r e t u r n [ N S S t r i n g s t r i n g W i t h C o n t e n t s O f F i l e : f i l e N a m e ] ; } @end i n t main ( v o i d ) { N S A u t o r e l e a s e P o o l ∗ p o o l ; F i l e R e a d e r ∗ r e a d e r ; NSConnection ∗ conn ; p o o l = [ N S A u t o r e l e a s e P o o l new ] ; /∗ Creamos e l o b j e t o F i l e R e a d e r ∗/ r e a d e r = [ F i l e R e a d e r new ] ; /∗ Obtenemos l a c o n e x i o n por d e f e c t o ∗/ conn = [ NSConnection d e f a u l t C o n n e c t i o n ] ; /∗ Hacemos a l l e c t o r d i s p o n i b l e p a r a o t r o s p r o c e s o s ∗/ [ conn s e t R o o t O b j e c t : r e a d e r ] ; /∗ R e g i s t r a m o s e s t o con e l nombre ‘ F i l e R e a d e r ’ ∗/ i f ( ! [ conn r e g i s t e r N a m e :@” F i l e R e a d e r ” ] ) { NSLog (@” I m p o s i b l e r e g i s t r a r n o s como F i l e R e a d e r ” ) ; e x i t ( 1 ) ; } NSLog (@” S e r v i d o r r e g i s t r a d o − e s p e r a n d o por c o n e x i o n e s . . . ” ) ; /∗ Ahora entramos a l c i c l o de e j e c u c i o n e s p e r a n d o p or c l i e n t e s ∗/

[ [ NSRunLoop currentRunLoop ] run ] ; r e t u r n 0 ;

(7)

5.

El cliente

El cliente se implementa en el archivo Client.m; este esta compuesto por la funci´on main del programa original, con algunos cambios muy interesantes.

5.1.

El protocolo FileReader

Puesto que la clase FileReader no esta compilada dentro del cliente (la hemos colocado dentro del servidor), no podemos referirnos a la clase FileReader en el cliente. Y por lo tanto, si necesitamos acceder el objeto remoto FileReader, necesitamos una forma de declarar que m´etodos soporta este.

Para manejar esta situaci´on, usamos un protocolo. Si se conoce Java, esto es muy similar a una interface. Un protocolo declara algunos m´etodos, dejando la implementaci´on sin especificar. El lenguaje nos permite entonces declarar un cierto objeto conforme a un protocolo; esto significa que el objeto implementa los m´etodos listados en el protocolo. En nuestro ejemplo, esto nos permite declarar que podemos enviar el mensaje getFile: al objeto lector (FileReader ), sin conocer actualmente la implementaci´on del m´etodo o la clase del objeto lector.

La declaraci´on de un protocolo es como sigue: @ p r o t o c o l F i l e R e a d e r

− ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end

Esto declara el protocolo FileReader para tener ´unicamente un m´etodo, get-File:. Los objetos conformes a este protocolo tienen un m´etodo getFile: que toman un NSString * como argumento y retornan un NSString *.

El objeto lector, que usamos declarado como de clase FileReader, F i l e R e a d e r ∗ r e a d e r ;

es ahora declarado mas gen´ericamente para estar conforme al protocolo Fil-eReader :

i d <F i l e R e a d e r > r e a d e r ;

id significa un objeto gen´erico; <FileReader> significa que este esta conforme al protocolo FileReader ; esto simplemente significa que el lector es un objeto al que se le puede enviar el mensaje getFile:.

5.2.

Accediendo al objeto remoto FileReader

Para acceder al objeto lector, el cual fue creado directamente, r e a d e r = [ F i l e R e a d e r new ] ;

ahora le requerimos a la librer´ıa gnustep-base que nos entregue el objeto registrado con el nombre FileReader en la maquina remota:

r e a d e r = ( i d <F i l e R e a d e r > ) [ NSConnection

r o o t P r o x y F o r C o n n e c t i o n W i t h R e g i s t e r e d N a m e : @” F i l e R e a d e r ” h o s t : @” ” ] ;

(8)

para ser preciso, el lector es un proxy local del objeto remoto - pero todo el proceso es realizado de tal forma que podemos prescindir de esta distinci´on, y pensar en el lector simplemente como un objeto remoto. Al usar una cadena vac´ıa para el argumento del host le estamos indicando a la librer´ıa gnustep-base que busque el objeto registrado con el nombre FileReader en el host local; si se conoce el host en el cual se quiere acceder al objeto FileReader, es mejor usar el nombre especifico de dicho host, algo como 192.168.29.1.

Necesitamos agregar <FileReader> porque la llamada a NSConnection re-torna un objeto gen´erico, pero nosotros sabemos que el objeto FileReader im-plementa getFile:. Una aplicaci´on m´as robusta podr´ıa verificar en tiempo de ejecuci´on si el objeto remoto puede actualmente responder al mensaje getFile: antes de hacer una llamada (por ejemplo, haciendo uso del m´etodo respondsToS-elector:); nosotros nos saltaremos esta peque˜na complicaci´on en nuestro primer ejemplo.

Pero debemos verificar que tenemos un objeto lector real - si este es nil, esto es porque por alguna raz´on la librer´ıa gnustep-base no puede conectar con el objeto registrado como FileReader en la red. Usualmente esto es porque el servidor no esta corriendo; no hay nada que podamos hacer en el cliente en estos casos, as´ı que simplemente se imprime un mensaje de error y salimos.

Como prometimos, el resto de la funci´on permanece sin cambio; en particu-lar, cuando nosotros enviamos el mensaje al m´etodo getFile: del objeto remoto, que inicia la conexi´on en la red con el servidor, y retorna el resultado - pero lo agradable aqu´ı es que no necesitamos hacer nada especial para realizar esta lla-mada remota; simplemente llamamos al m´etodo normalmente, como si el objeto fuera un amigable objeto local.

Aqu´ı esta el c´odigo fuente:

#i n c l u d e <Foundation / Foundation . h>

/∗ E s t e p r o t o c o l o nos i n d i c a como e l o b j e t o l e c t o r s e comporta ∗/ @ p r o t o c o l F i l e R e a d e r − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end i n t main ( v o i d ) { N S A u t o r e l e a s e P o o l ∗ p o o l ; NSArray ∗ a r g s ; i n t c o u n t ; i d <F i l e R e a d e r > r e a d e r ; N S S t r i n g ∗ f i l e n a m e ; N S S t r i n g ∗ f i l e ; p o o l = [ N S A u t o r e l e a s e P o o l new ] ;

(9)

/∗ Creamos e l o b j e t o l e c t o r ∗/ r e a d e r = ( i d <F i l e R e a d e r > ) [ NSConnection r o o t P r o x y F o r C o n n e c t i o n W i t h R e g i s t e r e d N a m e : @” F i l e R e a d e r ” h o s t : @” ” ] ; i f ( r e a d e r == n i l ) { NSLog (@” E r r o r : i m p o s i b l e c o n e c t a r con e l s e r v i d o r ” ) ; e x i t ( 1 ) ; }

/∗ Desde a q u i e l c o d i g o e s e l mismo , donde e l o b j e t o l e c t o r e s un p r o c e s o l o c a l o remoto ∗/

/∗ Obtenemos l o s argumentos d e l programa ∗/ a r g s = [ [ N S P r o c e s s I n f o p r o c e s s I n f o ] arguments ] ;

/∗ La p r i m e r a cadena en a r g s e s e l nombre d e l programa ; nos i n t e r e s a e l segundo argumento , s i hay ∗/

i f ( [ a r g s c o u n t ] == 1 ) {

NSLog (@” E r r o r : debe e s p e c i f i c a r un nombre de a r c h i v o ” ) ; e x i t ( 1 ) ; } f i l e n a m e = [ a r g s o b j e c t A t I n d e x : 1 ] ; /∗ Le pedimos a l o b j e t o l e c t o r e l a r c h i v o i n d i c a d o ∗/ f i l e = [ r e a d e r g e t F i l e : f i l e n a m e ] ; /∗ S i e l o b j e t o l e c t o r puede o b t e n e r e l a r c h i v o , m o s t r a r e s t e ∗/ i f ( f i l e != n i l ) { p r i n t f (” %s \n ” , [ f i l e l o s s y C S t r i n g ] ) ; } e l s e { NSLog (@” E r r o r : i m p o s i b l e l e e r e l a r c h i v o ‘ %@’ ” , f i l e n a m e ) ; e x i t ( 1 ) ; } r e t u r n 0 ; }

(10)

6.

Juntando todo

Para completar, aqu´ı esta el GNUmakefile:

i n c l u d e $ (GNUSTEP MAKEFILES) / common . make TOOL NAME = S e r v e r C l i e n t

Server OBJC FILES = S e r v e r .m Client OBJC FILES = C l i e n t .m

i n c l u d e $ (GNUSTEP MAKEFILES) / t o o l . make

Despu´es de compilar las dos herramientas, definitivamente hay que jugar con esto porque es realmente divertido. Lanzamos el servidor:

. / o b j / S e r v e r

Ahora abrimos otra terminal (en otra maquina de la misma red, si se tiene la fortuna de poder jugar en red), y lanzamos el cliente all´ı:

. / o b j / C l i e n t C l i e n t .m

esto despliega el archivo Client.m, como lo env´ıa el programa Server. En mi maquina esto trabaja de forma muy simple, inmediata y agradable, de forma que es dif´ıcil creer que el cliente a abierto una conexi´on en la red hacia el servidor, preguntado por un archivo, y que el servidor ha enviado este de vuelta a trav´es de la conexi´on. Para entender mejor que es lo que esta sucediendo, puede querer modificar la clase FileReader en el servidor para desplegar un log cada vez que este env´ıa un archivo:

@implementation F i l e R e a d e r

− ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e {

NSLog (@”Un c l i e n t e ha p r e g u n t a d o por e l a r c h i v o %@” , f i l e N a m e ) ; r e t u r n [ N S S t r i n g s t r i n g W i t h C o n t e n t s O f F i l e : f i l e N a m e ] ;

} @end

7.

Un cliente modificado que accede archivos

lo-cales y remotos

La secci´on previa fue una introducci´on a la magia negra de DO:, remplazamos un objeto local con uno remoto, y aun pudimos realizar llamadas en la forma usual. No necesitamos una sintaxis especial para mandar mensajes al objeto remoto, hicimos esto como con nuestros viejos y peque˜nos objetos en el proce-so local; el lenguaje y las librer´ıas manejaron silenciosamente el resto. Ahora queremos ir mas all´a: haremos el cambio en tiempo de ejecuci´on.

(11)

Queremos extender el cliente para que este pueda acceder archivos locales y remotos; este decidir´a que debe hacer dependiendo de los argumentos uti-lizados para llamarlo en la linea de comandos. Cuando se llame con un simple argumento, por ejemplo README,

C l i e n t README

este desplegara el archivo README desde la maquina local; cuando se llame con un archivo y un nombre de host, por ejemplo README y didone.gnustep.it.

C l i e n t README d i d o n e . g n u s t e p . i t

este desplegara el archivo README devuelto por el servidor corriendo en el host llamado didone.gnustep.it.

El servidor sera el mismo; solo debemos cambiar el cliente. Declaramos el protocolo FileReader de la forma usual ya que queremos tener un objeto lector que pueda ser local o remoto, y lo ´unico que sabemos es que podemos enviar el mensaje getFile: a este, que esta expresado en Objective-C diciendo que el objeto lector esta conforme al protocolo FileReader.

Entonces, implementamos la clase LocalFileReader, que lee un archivo (en la maquina local). Yo llamo a este LocalFileReader en lugar de FileReader para evitar confusiones, pero t´ecnicamente no hay nada que le impida llamarlo Fil-eReader. Esta es la clase usual, que implementa las facilidades para leer archivos locales. Pero la declaraci´on de la clase tiene una interesante modificaci´on:

@ i n t e r f a c e L o c a l F i l e R e a d e r : NSObject <F i l e R e a d e r > − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ;

@end

en esta declaraci´on, LocalFileReader desciende de NSObject, y esta conforme al protocolo FileReader. Declaramos que la clase implementa el protocolo puesto que esto nos permite conectar con cualquier objeto LocalFileReader mediante id <FileReader>.

Cuando el cliente esta corriendo, este examina los argumentos para decidir si necesita crear un objeto lector local o remoto.

/∗ Obtenemos l o s argumentos d e l programa ∗/ a r g s = [ [ N S P r o c e s s I n f o p r o c e s s I n f o ] arguments ] ; /∗ S i hay un segundo argumento ( s i n tomar en c u e n t a

e l nombre d e l programa c l a r o ) , l e e r e s t e como e l nombre d e l h o s t de donde debe o b t e n e r s e e l a r c h i v o ∗/ i f ( [ a r g s c o u n t ] > 2 ) { N S S t r i n g ∗ h o s t = [ a r g s o b j e c t A t I n d e x : 2 ] ; /∗ Creamos e l o b j e t o remoto F i l e R e a d e r ∗/ r e a d e r = ( i d <F i l e R e a d e r >) [ NSConnection

(12)

r o o t P r o x y F o r C o n n e c t i o n W i t h R e g i s t e r e d N a m e : @” F i l e R e a d e r ” h o s t : h o s t ] ; i f ( r e a d e r == n i l ) { NSLog (@” E r r o r : i m p o s i b l e c o n e c t a r con e l s e r v i d o r en e l h o s t %@” , h o s t ) ; e x i t ( 1 ) ; } }

e l s e /∗ S i no hay un segundo argumento − s e l e e e l a r c h i v o l o c a l ∗/ {

r e a d e r = [ L o c a l F i l e R e a d e r new ] ; }

y eso es todo; el c´odigo que sigue es el usual. Adviertase que ambos, el objeto local y el remoto, est´an conformes al protocolo FileReader, lo que hace posible que el c´odigo contacte el objeto local y remoto en forma limpia.

El cogido completo para el cliente es: #i n c l u d e <Foundation / Foundation . h>

/∗ E s t e p r o t o c o l o nos i n d i c a como e l o b j e t o l e c t o r s e comporta ∗/ @ p r o t o c o l F i l e R e a d e r − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end /∗ Un o b j e t o l e c t o r l o c a l c o n f o r m e a l p r o t o c o l o F i l e R e a d e r y que l e e a r c h i v o s l o c a l m e n t e ∗/ @ i n t e r f a c e L o c a l F i l e R e a d e r : NSObject <F i l e R e a d e r > − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end @implementation L o c a l F i l e R e a d e r − ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e { r e t u r n [ N S S t r i n g s t r i n g W i t h C o n t e n t s O f F i l e : f i l e N a m e ] ; } @end i n t main ( v o i d ) { N S A u t o r e l e a s e P o o l ∗ p o o l ; NSArray ∗ a r g s ;

(13)

i n t c o u n t ;

i d <F i l e R e a d e r > r e a d e r ; N S S t r i n g ∗ f i l e n a m e ; N S S t r i n g ∗ f i l e ;

p o o l = [ N S A u t o r e l e a s e P o o l new ] ;

/∗ Obtenemos l o s argumentos d e l programa ∗/ a r g s = [ [ N S P r o c e s s I n f o p r o c e s s I n f o ] arguments ] ; /∗ S i hay un segundo argumento ( s i n tomar en c u e n t a

e l nombre d e l programa c l a r o ) , l e e r e s t e como e l nombre d e l h o s t de donde debe o b t e n e r s e e l a r c h i v o ∗/ i f ( [ a r g s c o u n t ] > 2 ) { N S S t r i n g ∗ h o s t = [ a r g s o b j e c t A t I n d e x : 2 ] ; /∗ Creamos e l o b j e t o remoto F i l e R e a d e r ∗/ r e a d e r = ( i d <F i l e R e a d e r >) [ NSConnection r o o t P r o x y F o r C o n n e c t i o n W i t h R e g i s t e r e d N a m e : @” F i l e R e a d e r ” h o s t : h o s t ] ; i f ( r e a d e r == n i l ) { NSLog (@” E r r o r : i m p o s i b l e c o n e c t a r con e l s e r v i d o r en e l h o s t %@” , h o s t ) ; e x i t ( 1 ) ; } } e l s e /∗ A r c h i v o l o c a l ∗/ { r e a d e r = [ L o c a l F i l e R e a d e r new ] ; }

/∗ Desde a q u i e l c o d i g o e s e l mismo , donde e l o b j e t o l e c t o r e s un p r o c e s o l o c a l o remoto ∗/

/∗ La p r i m e r a cadena en a r g s e s e l nombre d e l programa ; nos i n t e r e s a e l segundo argumento , s i hay ∗/

i f ( [ a r g s c o u n t ] == 1 ) {

NSLog (@” E r r o r : debe e s p e c i f i c a r un nombre de a r c h i v o ” ) ; e x i t ( 1 ) ;

(14)

f i l e n a m e = [ a r g s o b j e c t A t I n d e x : 1 ] ; /∗ Le pedimos a l o b j e t o l e c t o r e l a r c h i v o i n d i c a d o ∗/ f i l e = [ r e a d e r g e t F i l e : f i l e n a m e ] ; /∗ S i e l o b j e t o l e c t o r puede o b t e n e r e l a r c h i v o , m o s t r a r e s t e ∗/ i f ( f i l e != n i l ) { p r i n t f (” %s \n ” , [ f i l e l o s s y C S t r i n g ] ) ; } e l s e { NSLog (@” E r r o r : i m p o s i b l e l e e r e l a r c h i v o ‘ %@’ ” , f i l e n a m e ) ; e x i t ( 1 ) ; } r e t u r n 0 ; }

NOTA: Si usted juega con el cliente, y si quiere pasar una cadena vac´ıa como nombre de host para que este busque en el host local, debe asegurarse de entrecomillar la cadena vac´ıa:

. / o b j / C l i e n t C l i e n t .m ’ ’

En este punto probablemente necesitamos decir unas pocas palabras acerca de porque y como es posible esta magia. En otras palabras, es tiempo de una peque˜na alabanza, sana y religiosa, a nuestro querido lenguaje Objective-C :-).

Toda la magia esta en el m´etodo de invocaci´on f i l e = [ r e a d e r g e t F i l e : f i l e n a m e ] ;

que llama al m´etodo getFile: del objeto lector, y donde no hay problema si el objeto lector es local o remoto; el tipo del objeto lector es determinado ´

unicamente durante el tiempo de ejecuci´on, dependiendo de los argumentos que se pasen a la herramienta en la linea de comandos. El ejemplo es impresionante porque muestra que el lenguaje nos permite sustituir cualquier objeto local en nuestra aplicaci´on con un objeto remoto en tiempo de ejecuci´on, sin tener que recompilar o reiniciar el c´odigo, y todo seguir´a funcionando, asumiendo por supuesto que el objeto remoto puede responder a los mismos m´etodos que el objeto local. Esto es posible porque Objective-C provee enlace din´amico para la llamada de m´etodos, lo que significa que la llamada del m´etodo solo se enlaza con su implementaci´on en tiempo de ejecuci´on. Esto permite muchos dise˜nos orientados a objetos de gran alcance, los cuales no serian posibles de otro modo (la Distribuci´on de Objetos son un ejemplo de semejante dise˜no); dise˜nos en los cuales los objetos son din´amica y limpiamente remplazados por otros objetos en tiempo de ejecuci´on, o dise˜nos en los cuales un objeto encapsula alguna

(15)

funcionalidad, pero la clase real o la implementaci´on del objeto no se conocen sino hasta el tiempo de ejecuci´on.

Objective-C es el lenguaje mas r´apido que soporta este dise˜no avanzado orientado a objetos; el c´odigo Objective-C es normalmente tan r´apido como C porque es c´odigo C, excepto en la llamada de m´etodos (lo cual no posee C) que en promedio toma tres veces m´as tiempo que el requerido para invocar una funci´on. Es pr´acticamente imposible para un completo lenguaje orientado a objetos ir m´as r´apido que eso; Objective-C realiza esto casi tan r´apido como C++, pero aun provee caracter´ısticas avanzadas y flexibles orientadas a objetos (como categor´ıas, o acceso interno en tiempo de ejecuci´on) que C++ no provee. Algunas de estas caracter´ısticas est´an ausentes incluso en Java.

8.

Verificaci´

on de errores - excepciones de

tiem-po de espera

Hasta ahora, este tutorial ha ignorado la comprobaci´on de errores; pero para construir aplicaciones robustas, el c´odigo debe ser capaz de manejar los problemas en las conexiones de red, tanto en el servidor como en el cliente.

En esta secci´on se examina el problema m´as simple: cuando se tiene un prob-lema durante la invocaci´on de un m´etodo a distancia, por lo general se produce una excepci´on de tiempo de espera en la conexi´on de red. Si el c´odigo en el cliente debe manejar objetos remotos en una forma s´olida, tiene que estar preparado para la captura y gesti´on de estas excepciones en las secciones pertinentes del c´odigo.

Una excepci´on de tiempo de espera significa que su cliente envi´o la llama-da del m´etodo al servidor, pero no obtuvo respuesta en un tiempo razonable. Despu´es de esperar durante 15 segundos (CORRIJANME - ´este era el antiguo valor por defecto para GNUstep-base, probablemente ha cambiado ahora), la biblioteca gnustep-base produce una excepci´on NSPortTimeOutException, que usted necesita capturar si desea escribir c´odigo robusto.

En nuestro ejemplo, tenemos que capturar las excepciones producidas du-rante la obtenci´on del archivo desde FileReader :

NS DURING { f i l e = [ r e a d e r g e t F i l e : f i l e n a m e ] ; } NS HANDLER { NSLog (@” M i e n t r a s s e l e i a e l a r c h i v o s e p r o d u j o l a e x c e p c i o n : %@” , l o c a l E x c e p t i o n ) ; e x i t ( 1 ) ; } NS ENDHANDLER

(16)

se captura la excepci´on es imprimir la descripci´on de la excepci´on y salir del programa - que es lo mismo que hace la librer´ıa gnustep-base por nosotros, si no capturamos la excepci´on... pero da un claro ejemplo de c´omo capturar y gestionar los tiempos de espera.

9.

Verificaci´

on de errores - la conexi´

on muere

Otro error t´ıpico que puede ocurrir es que la conexi´on muera. Como ejemplo, sup´ongase que tenemos un cliente modificado, en el cual obtenemos un objeto lector remoto, y donde el ciclo de ejecuci´on espera a que el usuario ingrese un nombre de archivo. Cuando este ingresa dicho nombre, se le pide al objeto remoto ese archivo y este se imprime en la salida, entonces se regresa al ciclo de ejecuci´on esperando a que el usuario ingrese el nombre de otro archivo.

En esa situaci´on, puede ocurrir que el servidor remoto este funcionando, pero en un momento dado, mientras estamos en nuestro ciclo de espera para que el usuario introduzca un nombre de archivo, el servidor remoto no este disponible (por ejemplo, a causa de un accidente de hardware, o porque la conexi´on de red deja de funcionar, o porque el servidor se encontr´o con un fallo de segmentaci´on durante alguna operaci´on). Si la biblioteca gnustep-base detecta este problema, se invalida el proxy para el objeto remoto (que en palabras sencillas significa que el objeto lector ya no es ´util, y no se puede usar mas), y env´ıa la notificaci´on NSConnectionDidDieNotification. Si estamos observando esta notificaci´on, podemos ser informados inmediatamente de que este problema se ha producido, y podr´ıamos manejar esto - podr´ıamos salir de la aplicaci´on de inmediato, tratar de conectar a otro servidor, o informar al usuario de que debido a que el servidor remoto esta muerto, s´olo se podr´an mostrar archivos locales hasta que se pueda conectar nuevamente al servidor remoto, o cualquier otra cosa. En cualquier caso, la notificaci´on nos da una oportunidad para liberar nuestro objeto lector - que ya no es ´util ya que la conexi´on ha muerto - y, si queremos y podemos, tomar algunas medidas correctivas. Aqu´ı est´a el c´odigo necesario para observar la notificaci´on:

[ [ N S N o t i f i c a t i o n C e n t e r d e f a u l t C e n t e r ] ad dO bse rv er : myObserver

s e l e c t o r : @ s e l e c t o r ( methodToExecuteWhenTheConnectionDies : ) name : N S C o n n e c t i o n D i d D i e N o t i f i c a t i o n

o b j e c t : [ ( N S D i s t a n t O b j e c t ∗ ) r e a d e r c o n n e c t i o n F o r P r o x y ] ] ; Ejecutando este c´odigo despu´es de que el objeto lector es creado, nos

asegu-ramos de que el m´etodo methodToExecuteWhenTheConnectionDies:, del objeto myObserver, sera llamado cuando la conexi´on con el servidor muera.

Aqu´ı el c´odigo de ejemplo de Client.m que se puede utilizar como punto de partida para gestionar conexiones muertas

-#i n c l u d e <Foundation / Foundation . h> @ p r o t o c o l F i l e R e a d e r

(17)

− ( NSString ∗ ) g e t F i l e : ( NSString ∗ ) f i l e N a m e ; @end @ i n t e r f a c e O b s e r v e r : NSObject − ( v o i d ) c o n n e c t i o n D i e d : ( N S N o t i f i c a t i o n ∗ ) not ; @end @implementation O b s e r v e r − ( v o i d ) c o n n e c t i o n D i e d : ( N S N o t i f i c a t i o n ∗ ) not {

NSLog (@”La c o n e x i o n con e l s e r v i d o r s e ha p e r d i d o − s a l i e n d o ” ) ; e x i t ( 1 ) ; } @end i n t main ( v o i d ) { N S A u t o r e l e a s e P o o l ∗ p o o l ; NSArray ∗ a r g s ; i n t c o u n t ; i d <F i l e R e a d e r > r e a d e r ; N S S t r i n g ∗ f i l e n a m e ; N S S t r i n g ∗ f i l e ; p o o l = [ N S A u t o r e l e a s e P o o l new ] ;

/∗ Obtenemos l o s argumentos d e l programa ∗/ a r g s = [ [ N S P r o c e s s I n f o p r o c e s s I n f o ] arguments ] ; /∗ Creamos e l o b j e t o remoto F i l e R e a d e r ∗/ r e a d e r = ( i d <F i l e R e a d e r >) [ NSConnection r o o t P r o x y F o r C o n n e c t i o n W i t h R e g i s t e r e d N a m e : @” F i l e R e a d e r ” h o s t : @” ” ] ; i f ( r e a d e r == n i l ) { NSLog (@” E r r o r − i m p o s i b l e c o n e c t a r con e l s e r v i d o r F i l e R e a d e r ” ) ; e x i t ( 1 ) ; } e l s e { NSLog (@” Conectado ” ) ; }

(18)

/∗ R e g i s t r a m o s a l Observador −c o n n e c t i o n D i e d : p a r a s e r i n f o r m a d o s a l momento de que l a c o n e x i o n con e l s e r v i d o r muere . ∗/

[ [ N S N o t i f i c a t i o n C e n t e r d e f a u l t C e n t e r ] ad dO bse rv er : [ O b s e r v e r new ] s e l e c t o r : @ s e l e c t o r ( c o n n e c t i o n D i e d : ) name : N S C o n n e c t i o n D i d D i e N o t i f i c a t i o n o b j e c t : [ ( N S D i s t a n t O b j e c t ∗ ) r e a d e r c o n n e c t i o n F o r P r o x y ] ] ; /∗ Bien − a h o r a entramos a l c i c l o de e j e c u c i o n . En e s t e e j e m p l o , no hacemos nada en e s t e c i c l o ya que t e n g o p e r e z a p a r a e s c r i b i r c o d i g o y h a c e r a l g o −− p e r o u s t e d puede i m a g i n a r que e s t e e s un s e r v i d o r h a c i e n d o una g r a n c a n t i d a d de c o s a s en e l c i c l o de e j e c u c i o n , y usando a l ’ l e c t o r ’ p a r a o b t e n e r a r c h i v o s d e s d e

s e r v i d o r e s r e m o t o s cuando su a c t i v i d a d en e l c i c l o de e j e c u c i o n l o r e q u i e r a . ∗/

[ [ NSRunLoop currentRunLoop ] run ] ; r e t u r n 0 ;

}

Ahora puede jugar ejecutando el servidor en una terminal, y ejecutando el cliente en otra, entonces matar el servidor en la primera terminal (por ejemplo pulsando Control-C): ¡el cliente en la segunda terminal debe ser inmediatamente notificado de que la conexi´on con el servidor est´a muerta!

10.

Para mas informaci´

on

En este tutorial se presentaron los conceptos b´asicos de los Objetos Distribui-dos, pero hay muchas otras cosas interesantes para explorar. Un buen punto de partida para m´as diversi´on con objetos distribuidos es la documentaci´on de NSConnection. Un ejemplo muy completo (pero tal vez bastante complejo) es la herramienta gdnc en el directorio Tools de la librer´ıa gnustep-base.

Referencias

Documento similar

Cedulario se inicia a mediados del siglo XVIL, por sus propias cédulas puede advertirse que no estaba totalmente conquistada la Nueva Gali- cia, ya que a fines del siglo xvn y en

quiero también a Liseo porque en mi alma hay lugar para amar a cuantos veo... tiene mi gusto sujeto, 320 sin que pueda la razón,.. ni mande

En estos últimos años, he tenido el privilegio, durante varias prolongadas visitas al extranjero, de hacer investigaciones sobre el teatro, y muchas veces he tenido la ocasión

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

Products Management Services (PMS) - Implementation of International Organization for Standardization (ISO) standards for the identification of medicinal products (IDMP) in

This section provides guidance with examples on encoding medicinal product packaging information, together with the relationship between Pack Size, Package Item (container)

Package Item (Container) Type : Vial (100000073563) Quantity Operator: equal to (100000000049) Package Item (Container) Quantity : 1 Material : Glass type I (200000003204)

El Tratado de Maastricht introduce como elemento fundamental de la Unión Europea la cooperación en los ámbitos de la justicia y en los asuntos de interior (JAI) y establece la doble