Composición y Coordinación de Componentes mediante Conectores y WebServices

Composición y Coordinación de Componentes mediante Conectores y WebServices M. Katrib Facultad de Matemática y Computación. Universidad de la Habana m

1 downloads 86 Views 89KB Size

Recommend Stories


ESTRUCTURAS MIXTAS Y CONECTORES
ESTRUCTURAS MIXTAS Y CONECTORES Cuando dos materiales distintos se mantienen unidos de forma eficaz se comportan, desde un punto de vista estructural,

CONECTORES Y MARCADORES
CAPÍTULO V CONECTORES Y MARCADORES Para explicar el uso de los conectores y marcadores del discurso es necesario adoptar una perspectiva pragmático-

Story Transcript

Composición y Coordinación de Componentes mediante Conectores y WebServices M. Katrib Facultad de Matemática y Computación. Universidad de la Habana [email protected]

J.L. Pastrana E.T.S.I. Informática. Universidad de Málaga [email protected]

E. Pimentel E.T.S.I. Informática. Universidad de Málaga [email protected]

Resumen La reutilización de componentes es uno de los principales objetivos que se plantean en la ingeniería del software actual. El siguiente trabajo, que continúa la línea emprendida en trabajos anteriores, muestra cómo una extensión de la metáfora del "Diseño por Contrato" puede ser usada como herramienta simple y elegante para la composición, coordinación y reutilización de componentes software previamente existentes. Para ello se definen conectores en forma de contratos (precondiciones, postcondiciones e invariantes) y comportamientos impuestos al servidor (en caso de incumplimiento de los mismos) entre componentes mediante la extensión del interfaz del componente servidor (en el que se expresan sus características funcionales) con los requisitos no funcionales que el componente cliente desea. Un conector será, por tanto, un componente, cuya implementación es generada de forma automática a partir de su definición, y será el encargado de conectar, coordinar, sincronizar y modelar el comportamiento en caso de fallo del componente remoto que queremos usar desde uno o varios componentes. De esta forma, el uso de estos conectores nos permitirá tener un software, basado en la composición de componentes previos ya existentes, que sea de calidad, tolerante a fallos y conceptualmente distribuido A nivel de implementación, se propone una herramienta que genera automáticamente dichos conectores a partir de descripción funcional extendida (IDL + Contratos) con lo que separa los detalles semánticos y de comportamiento de los de los detalles funcionales y de implementación. Versiones anteriores de la herramienta se basan en Java usando AspectJ y bajo el estándar CORBA de OMG y en C# usando .NET. En este trabajo se propone también una herramienta que utiliza WebServices y tecnología XML para la implementación de los conectores. La posibilidad de definir uno o más conectores diferentes para un mismo componente remoto y el hecho de ser el cliente quién imponga el comportamiento que desea del componente remoto que actúa de servidor hace que se pueda tener más de un comportamiento diferente de un mismo componente remoto en función de quién lo use. Esto posibilita una mayor reutilización de componentes en lo que podríamos llamar "Software Orientado al Cliente".

1. Introducción Trabajos precedentes, [5, 6, 7, 8], presentan un modelo para el desarrollo de software basando en la composición de componentes a los que se le establece como necesaria una clara separación entre los aspectos computacionales de los componentes respecto a otros requisitos no funcionales que son susceptibles de cambiar durante su ciclo de vida. Entre estos requisitos podemos citar: sincronización, coordinación, persistencia, replicación, distribución, tiempo real, etc. Recordemos qué entendemos por componente y las características que debe tener un componente para permitir el desarrollo de software mediante composición de los mismos: Componentes son unidades Software binarias que pueden ser insertados en un sistema y puestos a trabajar. Se entiende por binario el que sea ejecutable por una máquina (mas o menos directamente, i.e. no necesariamente código nativo para un CPU concreto sino incluso un código virtual) y no que sea el código

máquina para un procesador dado o que no sea legible por un humano, para que puedan ser usadas como unidades de desarrollo. Siete Criterios para Componentes: 1. Pueden ser usados por otros elementos Software (Clientes). 2. Pueden ser usados por clientes sin la intervención de sus desarrolladores. 3. Incluyen una especificación de todas las dependencias. 4. Incluyen una precisa especificación de la funcionalidad que ofrece. 5. Sólo pueden ser usados basándose en su especificación. 6. Es componible con otros componentes. 7. Pueden ser integrados rápida y suavemente en un sistema Para poder expresar los requisitos no funcionales de un componente, sus interfaces deberían ser enriquecidas con definiciones semánticas, requerimientos de sincronización y de comportamiento ante fallos para poder asegurar un correcto comportamiento de los mismos, de modo que, la composición de componentes alcance a realizar el objetivo deseado del sistema software. Nuestra propuesta se basa en la definición de conectores entre componentes. Dichos conectores, no son simples adaptadores de interfaces que sólo adapten el nombre de las operaciones o el tipo de los parámetros. Son componentes activos que permiten la definición de requisitos vía asertos, así como la definición del comportamiento ante el incumplimiento de los mismos. La posibilidad de definir más de un conector (con requisitos y comportamientos diferentes) sobre un mismo componente remoto permite una mayor reutilización de un componente, ya que un mismo componente servidor puede ser usado con diferentes comportamientos por varios componentes clientes. Considérese el siguiente ejemplo: un componente productor y otro consumidor se sincronizan a través de un componente buffer acotado. La circunstancia de que el productor intente colocar un elemento sobre un buffer lleno o que el consumidor intente extraer un elemento sobre un buffer vacío no debe considerarse un error, s ino una simple sincronización entre componentes. Sin embargo, supongamos que el productor, por ejemplo, usa un buffer acotado en el proceso de producción (además del que ya usa para comunicarse y sincronizarse con el consumidor) que podría ser una instancia diferente de la misma clase de componente buffer. En este caso, si podríamos considerar como un error el intentar extraer elementos sobre el buffer vacío o insertar sobre el buffer lleno. ¿Significa esto que el funcionamiento de ambos buffer es diferente? La respuesta es NO (de hecho podrían ser instancias diferentes de la misma clase de componente buffer). La diferencia radica en los requisitos no funcionales y/o en el comportamiento del mismo ante el incumplimiento de los mismos, que es precisamente lo que modela el conector. La solución a problemas de cambios de requisitos o de escalabilidad es simple, sencilla y conocida desde hace años. Al igual que cualquier producto hardware está compuesto por un conjunto de componentes interconectados, los productos software deben seguir la misma filosofía y estar formados por un conjunto de componentes software conectables, de manera que pueda ser sustituido un componente, si es necesario, o cambiar la conexión o tipo de ésta. Esta filosofía o arquitectura software de composición, además de permitir el desarrollo de un software más flexible y escalable, permite no hacer diferencias entre sistemas distribuidos y no distribuidos, ya que la localización de los componentes no afecta a la funcionalidad del sistema (aunque como es obvio puede afectar a la eficiencia del mismo). En la presente propuesta, se extiende la semántica del contrato (precondiciones, postcondiciones e invariantes) [12] de manera que pueda ser usada para garantizar la coordinación de componentes. Esta coordinación se realizará a través de las cláusulas de comportamiento ante fallo que permitirán la suspensión de la llamada hasta que se verifique la condición, el fallo de la llamada (excepción) o el reintento de la misma. Todos los conectores de comp onentes del sistema tendrán, también, la posibilidad del uso de un predicado especial timeout con un parámetro real para especificar los requerimientos temporales de cualquier servicio. Es importante notar que, a diferencia del modelo original propuesto por Meyer [12] en el que los asertos se verifican en el componente servidor, en este modelo, es el conector el encargado de verificar los asertos que el cliente exige para un servicio (precondición) o propone como invariante o postcondición. Esto significa que no es el componente que ofrece el servicio quién asegura el funcionamiento, sino que es el

cliente quien impone las condiciones de funcionamiento particulares para él. Es decir, es el cliente quien decide en qué condiciones quiere que se ejecuten sus peticiones.

2. Ejemplo: Una Biblioteca Virtual. Supongamos que se tiene una biblioteca virtual donde se pueden leer diferentes revistas o libros. Para ello tenemos un servidor que puede ser accedido por diferentes navegadores. Dicho servidor, también debe ser actualizado, modificando la información que él contenga. Esta aplicación, por tanto, tendría un número indeterminado de componentes (instancias reales), pero que corresponden a 3 clases de componentes: navegadores, administradores y servidor. El interfaz (IDL) del servidor podría ser como el siguiente: interface ServidorBiblio { String Consultar(); void Administrar(); void establecer_deseo_administrar(boolean deseo); boolean esta_siendo_administrado(); boolean desea_ser_administrado(); };

Código Fuente 1. Interfaz del Servidor de la Biblioteca Veamos cómo a partir de esa interfaz, se puede diseñar los conectores para que puedan interaccionar con él, tanto los navegadores como los administradores. Un navegador, podrá consultar siempre que no esté siendo modificado, o se desee modificar el servidor y nunca podrá administrar, mientras que el administrador precisa exclusión mutua para modificar el servidor. Connector ConectorNavegador define ServidorBiblio { String Consultar() { Require: (!esta_siendo_administrado()) && (!desea_ser_administrado()) On Failure: Suspend; // Esperamos cuando está o desea ser administrado }; void Administrar() { Require: false On Failure: throw new ExcepcionDeAcceso(); // Servicio no habilitado para un cliente Navegador. }; void establecer_deseo_administrar(boolean deseo) { Require: false On Failure: throw new ExcepcionDeAcceso(); // Servicio no habilitado para un cliente Navegador. }; boolean esta_siendo_administrado() { /* No requiere Precondición. Es equivalente a Require: true Hemos colocado toda la interfaz para que se tenga una visión completa de los servicios ofrecidos por el componente, pero para aquellos servicios que no se vaya a expresar ningún aserto, no es necesario incluirlos en el conector.*/ }; boolean desea_ser_administrado() { // No requiere Precondición. Es equivalente a Require: true }; };

Código Fuente 2. Conector para el Navegador del Servidor WWW Connector ConectorAdministrador define ServidorBiblio { String Consultar() { Require: false // Servicio no habilitado

On Failure: throw new ExcepcionDeAcceso(); };

void Administrar() { Require: Available() //Requiere exclusión mutua. On Failure: Suspend; }; void establecer_deseo_administrar(boolean deseo) { }; / No requiere Precondición. boolean esta_siendo_administrado() { }; / No requiere Precondición. boolean desea_ser_administrado() { }; / No requiere Precondición. };

Código Fuente 3. Conector para el Administrador del Servidor WWW Nótese que el diseño del conector está siendo utilizado también para expresar de forma explícita la prohibición de un determinado tipo de clientes para usar determinado tipo de servicios del servidor. En el ejemplo anterior, al imponer como precondición false la llamada al servicio de administrar para el caso de los navegadores, se está especificando que dicho cliente no podrá nunca satisfacer esa precondición y siempre será elevada la excepción de "falta de privilegio". Una vez ya definidos los conectores, cualquier usuario o en cualquier componente, podría usarlos para acceder a nuestro servidor.

3. Desarrollo de Conectores Avanzados. Un conector es también un componente, por tanto, cabe plantearse el uso de técnicas tradicionales de desarrollo y mejora de componentes a través de técnicas como la herencia, composición y delegación en el desarrollo de nuevos conectores.

3.1 Herencia La herencia se usa en el ámbito de la programación orientada a objetos y componentes para: • Concretización: Reemplazo de métodos abstractos por métodos concretos. • Extensión: Añadir nuevos métodos. • Refinamiento: Escribir métodos que ofrecen un mejor servicio que sus predecesores. Parece adecuado que se pueda utilizar la herencia a la hora de mejorar o definir nuevos conectores. Por ejemplo, supongamos que se tiene un componente buffer acotado con la siguiente interfaz: interface Buffer { bool isEmpty(); bool isFull(); int get(); void put(in int x); };

Código Fuente 4. Interfaz del Buffer Acotado A partir de esa interfaz podríamos haber desarrollado un conector para usar dicho componente en una aplicación secuencial en la que sería erróneo extraer información del buffer vacío o insertarla en un buffer lleno. Definiendo un conector como el que se muestra a continuación: Connector BufferConnector define Buffer { int get() { Require: !isEmpty(); On Failure: Fail; }; void put(in int x) { Require: !isFull(); On Failure: Fail;

}; };

Código Fuente 5. Conector del Buffer Acotado Supongamos que queremos usar el mismo buffer para sincronizar una aplicación en la que un componente productor y otro consumidor trabajan concurrentemente. En vez de definir un conector completamente nuevo, podemos refinar el conector anterior usando la herencia: Connector ConsumerBufferConnector extend BufferConnector { int get()

{ Require:

!isEmpty();

On Failure: Suspend;

}; };

Código Fuente 6. Conector del Buffer del Consumidor Connector ProducerBufferConnector extend BufferConnector { void put(in int x)

{ Require:

!isFull();

On Failure: Suspend;

}; };

Código Fuente 7. Conector del Buffer del Productor La herencia puede redefinir comportamientos o añadir comportamientos nuevos para un mismo componente remoto de manera estática. Se puede representar como una relación "es un/a", por ejemplo, un ConsumerBufferConnector es un BufferConnector. Los contratos y comportamiento de un conector "hijo" sustituyen a los del padre salvo que no sean redefinidos.

3.2 Delegación La delegación es una relación entre componentes donde uno delega en otros los servicios que éste no es capaz de resolver. Este mecanismo se convierte en una herramienta muy útil y flexible cuando es posible modificar en tiempo de ejecución el componente en el cuál se delega. La siguiente sentencia predefinida permitirá a un conector modificar en tiempo de ejecución el conector en el cuál delega: void DelegateOn(string connector_name) (donde connector_name debe ser el nombre simbólico con el que el conector está registrado en el servicio de nombres del sistema) . Siguiendo con el ejemplo anterior, el uso de la delegación podría incrementar la tolerancia ante fallos de nuestro conector, pudiendo, por ejemplo, cambiar el conector en que delega en caso de que el tiempo de respuesta de una llamada supere una cota establecida. En el ejemplo anterior: Connector FT_BufferConnector define Buffer { int get() { Require: timeout(10.0) On Failure: DelegateOn(second_connector_name); retry; } void put(in int x) { Require: timeout(10.0) On Failure: DelegateOn(second_connector_name); retry; }; };

Código Fuente 8. Conector Tolerante a Fallos vía Delegación El uso de la delegación permite la modificación del conector a través del cual accedemos a los servicios ofrecidos por un componente remoto en tiempo de ejecución, lo que nos permite cambiar de comportamiento (si el nuevo conector tiene un comportamiento diferente) y/o cambiar de componente servidor (si el nuevo

conector está enlazado a un componente distinto).En este caso, el sistema puede incluir mecanismos de tolerancia a fallos basados en buscar nuevos conectores en caso de que algún componente no responda o que los resultados que nos ofrezca no sean de nuestro agrado. La delegación, por tanto, puede verse como una relación del tipo “tiene un/a” por lo que un FT_BufferConnector “tiene un” Buffer.

3.3 Composición. La composición de conectores es su aplicación encadenada uno tras otro. Por tanto, se comportarán como filtros. Esto puede ser útil cuando se desea endurecer las restricciones de precondición para un servicio, ya que deberá satisfacer todas las precondiciones (conjunción de precondiciones). Además, se ejecutarán todas las sentencias On Failure correspondientes a todos los conectores cuyas precondiciones no hayan sido satisfechas. Por ejemplo, basándonos en el ejemplo anterior del buffer, podemos generar un conector que requiera exclusión mutua para el acceso al buffer. Connector MutualExclusionBufferConnector before BufferConnector { bool isEmpty() { Require: Available(); } bool isFull() { Require: }

Available();

int get() { Require: }

Available();

void put(in int x) { Require: Available(); }; };

Código Fuente 9. Conector Buffer con Exclusión Mutua. Por tanto, la composición es útil cuando se desea añadir un comportamiento a un conector que no lo tiene definido para ese servicio y se desea hacerlo más estricto sin necesidad de parar la ejecución del componente remoto. Por ejemplo, en este caso, bastaría con generar el nuevo conector que va “antes” del que estamos usando y luego, o bien simplemente usar una sentencia de DelegateOn para cambiar dinámicamente el conector a través del que accedemos a los servicios, o bien, solamente parar el cliente para modificar en nuestro código el conector a usar. La composición es una relación de agregación, es decir en nuestro ejemplo tendremos un MutualExclusionBufferConnector más un BufferConnector.

4. Implementación de Conectores. Hemos desarrollado una herramienta (de la que actualmente tenemos dos posibles implementaciones: una en Java usando AspectJ y bajo el estándar CORBA de OMG y otra en C# usando .NET), que separa los detalles semánticos y de comportamiento tanto de los de los detalles funcionales como de implementación y cuyos detalles de implementación han sido comentados en los trabajos previos. La última versión de nuestra herramienta (que está en fase de pruebas) utiliza servicios web y tecnología XML para el desarrollo de los conectores con el fin de obtener una mayor heterogeneidad en los usuarios de la herramienta y estandarización en los protocolos de comunicación. Los trabajos [9, 18] encaminados a la inclusión de asertos y aspectos en .NET pueden ser una herramienta muy útil y elegante a la hora de la implementación de los conectores, de forma que se pueda generar más código reflexivo y menos traducción fuente a fuente.

4.1 Estudio del uso de WebServices en la implementación de Conectores. Al igual que en las implementaciones anteriores con CORBA o TCP.NET, partimos de la idea de conectar, coordinar y sincronizar un número, a priori, indeterminado de componentes ACTIVOS , es decir, no son DLL’s sino procesos que están ejecutándose en una máquina virtualmente remota. El esquema de comunicación sería el siguiente:

Figura 1. Esquema de Comunicación Usando Corba ó TCP.NET ¿Qué posibilidades habría de usar la tecnología XML y los servicios Web para el desarrollo de los conectores? a.) Usar WebServices para interconectar los diferentes componentes activos (en la figura 1 donde pone CORBA). Tiene la ventaja de que estandariza la comunicación, pero básicamente lo que se hace es usar WebServices como middleware de comunicación. b.) Implementar el conector mediante un WebService en el que el componente servidor es un componente local al WebService. Si bien la sensación es buena y parece que todo funciona bien y sencillo, tiene el problema de que perdemos uno de los objetivos o ideas iniciales, ya que de esta forma el conector va “pegado” al servidor y ya no es el cliente el que “impone” los requerimientos y comportamientos. c.) Implementar el conector mediante un WebService en el que tenemos una referencia a un componente remoto. A diferencia del apartado ‘a’ el servicio Web no sólo se encarga de la comunicación, sino también, de la evaluación de contratos, ejecución de sentencias en caso de fallo y planificación de peticiones en caso de que haya sentencias Suspend. Con esta opción, al tener una implementación basada en XML y WS con lo que conseguimos la heterogeneidad de los clientes sin perder ninguna característica respecto al modelo anterior.

Figura 2. Esquema de Comunicación Usando XML y WebServices A la hora de realizar una implementación basada en la opción ‘c’ surge un problema: Los WebServices no tienen estado, es decir, se crean al efectuar una llamada y luego se destruyen. ¿Cómo entonces podemos realizar la parte de planificación que realiza el conector? ¿Cómo suspender a un llamante si luego no puedo despertarlo? Hay una solución “factible” que consiste en declarar como estáticos las variables que conforman el estado del conector: enlace al servidor, lista de peticiones suspendidas, lista de precondiciones, lista de parámetros de dichas precondiciones, número de peticiones suspendidas, etc. Sin embargo, seguimos estudiando otras posibles soluciones más elegantes.

5. Trabajos Relacionados El presente trabajo presenta una propuesta para el desarrollo de software orientado a componentes a partir de componentes ya existentes, así como su coordinación y sincronización. Veamos algunos trabajos relacionados. Existen propuestas como iContract [10] o jContract [14] que incorporan el modelo de contrato para el lenguaje Java. Sin embargo, son propuestas basadas en objetos y no en componentes y para diseño de aplicaciones secuenciales, por lo que no son aplicables en el contexto de componentes distribuidos. Otros trabajos como [5, 6, 7, 8] incorporan el concepto de contrato como herramienta de sincronización para hebras y objetos separate. Quizá los trabajos, a priori, más relacionados serían los relacionados con la programación orientada a aspectos (POA). Sin embargo, nuestra propuesta se basa en definir aspectos no funcionales sobre componentes remotos sobre los cuales no podemos tejer aspectos. Por otra parte, mediante el uso de la POA sería complicado el poder tener diferentes comportamientos para una misma llamada y un mismo componente remoto (cosa que es factible y sencilla, bastaría con tener 2 conectores diferentes para un mismo componente), en lo que hemos llamado “Software orientado al Cliente”. En esta línea, AspectIX [4], por ejemplo, pretende ser un middleware, una extensión de CORBA, que permita tejer aspectos. Sin embargo, y a diferencia con CORBA, AspectIX adopta una arquitectura que sigue un modelo de objetos fragmentados al estilo de INRIA, en el que un objeto distribuido consiste en un conjunto de fragmentos que pueden interactuar y en el que el cliente de un objeto siempre tiene al menos uno de esos fragmentos (en el caso de CORBA su Stub). AspectIX utiliza un tejedor estandar para Java y entrelaza los aspectos con las llamadas que se realizan en los Stubs. Esto, imposibilita la definición de comportamientos diferentes para un mismo componente remoto (ya que el Stub es único) y no permite el uso de aspectos no funcionales para la sincronización de componentes, por ejemplo, la suspensión de una llamada si no se verifica cierta propiedad antes de ejecutarla, ya que no habría quién la despertara. Otra propuesta, en la misma línea de la anterior, es la de Dinamic Wrappers propuestos en JAC (Java Aspect Compiler) [15]. Esta propuesta, utiliza envoltorios para los métodos, que pueden ser modificados dinámicamente, para implementar el uso de aspectos en sistemas distribuidos. Si bien, el comportamiento puede ser modificado dinámicamente, no se pueden tener dos comportamientos distintos al mismo tiempo y existiría el mismo problema cara a la sincronización que en el caso anterior. Los primeros trabajos de Cristina Lopes [11] en el campo del lenguaje de coordinación COOL, en el cuál e xiste un coordinador que se adjunta a cada objeto en tiempo de compilación pueden parecer equivalentes a los conectores propuestos, sin embargo, hay una gran diferencia. El coordinador de COOL está adjunto al componente servidor y es éste y no el cliente quien impone los requisitos no funcionales, mientras que en nuestro caso, es el cliente el que impone tanto dichos requisitos como el comportamiento ante su posible incumplimiento. En esta línea, el modelo Coordinated Roles [13] mejora los trabajos de Lopes en el sentido de que es capaz de generar, componer y cambiar los conectores en tiempo de ejecución. Está fuertemente influenciado por las propuestas de Aksit y parece que aporta todas las facilidades descritas en este trabajo y algunas más (como la posibilidad de definir patrones de coordinación complejos entre varios objetos), sin embargo, y al igual que muchos otros trabajos que van en esta línea (como [1, 3]) todos ellos tiene el mismo problema: el servidor es quién impone “su ley”. Para finalizar la comparación con trabajos similares y dado que enmarcamos nuestra implementación en la tecnología de .NET y C#, debemos hacer mención a Polyphonic C# [2]. Polyphonic C# es una extensión del lenguaje C# con un mecanismo de abstracción de la concurrencia basado en el cálculo de uniones. Si bien el modelo se nos presenta como válido para un sistema multihebras y para un

sistema de una “orquesta” de procesadores, en este caso, el sistema está orientado a eventos y no a llamadas a servicios. Por otra parte, la unión de cálculos que permiten la coordinación como por ejemplo: public String get() & private async contains(String s) se realiza en el servidor con lo que volvemos a tener el mismo problema que con las propuestas anteriores: el servidor es quién impone “su ley”. Sin embargo, esta idea que propone Polyphonic C# puede ser interesante cara a una nueva forma de definir los conectores y como herramienta para su implementación en futuras versiones.

6. Conclusiones y Trabajos Futuros. La presente propuesta ofrece al diseñador una herramienta basada en asertos (contratos) para expresar requisitos no funcionales como la coordinación/sincronización de componentes distribuidos de manera que es el cliente quien impone el comportamiento no funcional de cada componente remoto que desea utilizar, lo que permite una mayor flexibilidad y reutilización de los componentes ya existentes (por ejemplo dos clientes pueden tener diferente comportamiento de un mismo componente remoto). La herramienta encargada de la generación de código ha sido llamada ComponentsDxC y es capaz de generar todo el código que implementa un conector a partir de su definición (IDL extendida). La primera versión fue desarrollada para generar Java /CORBA, la segunda versión genera C#/ bajo dot-Net. Y actualmente se están generando WebServices (desarrollados en C#) para la implementación de los conectores lo que los hace más independientes de los componentes que conecta. Actualmente, ya dado que las nuevas versiones van orientadas al mundo de los servicios Web, se está estudiando la posibilidad de modificar al sintaxis de definición de los conectores basándonos en los lenguajes de definición de estos servicios y usando atributos o uniones de cálculo para expresar los asertos. Como trabajo futuro se desea la mejora de la herramienta para que sea más amigable (actualmente es textual), su posible combinación con herramientas o lenguajes de composición, así como estudiar la posibilidad del uso de predicados de periodicidad para realizar planificaciones de tiempo real.

Referencias [1] Aksit M., Wakita K., Bosch J., Bergmans L., Yonezawa A., Abstracting Object Interactions Using Composition Filters, Proceedings of the Workshop on Object-Based Distributed Programming, ECOOP'93, 152--184, Lecture Notes in Comput er Science 791, 1994 [2] Benton N., Cardelli L., Fournet C., Introduction to Polyphonic C# http://research.microsoft.com/~nick/polyphony [3] Frolund S., Agha G., A Language Framework for Multi-Object Coordination, Proceedings of the European Conference on Object-oriented Programming ECOOP'93, 346--360, 1993 [4] Hauck F., Becker U., Geier M., "AspectIX: A Middleware for Aspect-Oriented Programming.", Workshop on Aspect -Oriented Programming. ECOOP'98,Bruselas (Bélgica), 1998. [5] Katrib, M. Fernández, D. “JavaA: inclusión de aserciones en Java”, Revista Computación y Sistemas,, México, 1999 [6] Katrib, M. Pimentel, E. “Synchronizing Java threads using assertions”, Proceedings of TOOLS 31th, Editors, IEEE Computer Society, ISBN: 0-7695-393-4. , Asia 1999 [7] Katrib, M., Pastrana J.L., Pimentel E. "Coordinación de Objetos Separate en Java" , 4º Workshop Iberoamericano de Ingeniería de Requisitos y Ambientes Software. IDEAS'201, San José (Costa Rica) 201. [8] Katrib, M., Pastrana J.L., Pimentel E. "Conectores: Una Solución para la Composición y Coordinación de Componentes”, en: 6º Workshop Iberoamericano de Ingeniería de Requisitos y Ambientes Software. IDEAS'203, Asunción, Paraguay (203) . [9] Katrib, M.,Ledesma E., Including assertion attributes in .NET assemblies en .NET Developer’s Journal, USA, September 2003 [10] Kramer R. “iContract - The Java TM Design by Contract TM Tool”. Proceedings of Technology of Object -Oriented Languages and Systems 26th International Conference and Exhibition. 1998 [11] Lopes, D: A Language Framework for Distributed Programming, Xerox Palo Alto Research Center, 1998 [12] Meyer, B. Construcción de Software Orientado a Objetos, Prentice Hall 1999 [13] Murillo J.M., Hernández J., Sánchez F, Álvarez L.A., Coordinated Roles: Promoting Re-usability of Coordinated Active Objects Using Event Notification Protocols, Proceedings of the COORDINATION'99 Conference, 53--68, 1999

[14] Parasoft Corporation. Using Design by Contract[TM] to Automate Java[TM] Software & Component Testing http://www.parasoft.com/ [15] Pawlak R., Seinturier L., Duchien L., "Dynamic wrappers: handling the composition issue with JAC", TOOLS, Santa Bárbara (EEUU) 202 [18] Schult W., Polze A. Aspect-Oriented Programming with C# and .NET

Get in touch

Social

© Copyright 2013 - 2024 MYDOKUMENT.COM - All rights reserved.