Animación Automática de Especificaciones OASIS utilizando
Transcripción
Animación Automática de Especificaciones OASIS utilizando
Animación Automática de Especificaciones OASIS utilizando Programación Lógica Concurrente Patricio Orlando Letelier Torres Departamento de Sistemas Informáticos y Computación Universidad Politécnica de Valencia Memoria para optar al Grado de Doctor en Informática Dirigida por el Prof. Dr. Isidro Ramos Salavert ii Abstract El modelo conceptual expresa los requisitos funcionales de un sistema de información. Errores u omisiones en el modelo conceptual tienen por lo general graves consecuencias en el resto del proceso de desarrollo de software. Por esto, la validación temprana de requisitos es una actividad de reconocida importancia. En este sentido, los enfoques más extendidos incluyen técnicas semiformales y en particular prototipación. Sin embargo, el resultado obtenido está lejos de ser satisfactorio. La combinación de técnicas formales con prototipación abre nuevas perspectivas, en especial la prototipación basada en especificaciones formales ejecutables y denominada animación de especificaciones. El desafío en este caso está en la capacidad para obtener código ejecutable a partir de una especificación, más aún si se pretende conseguir la generación automática de dicho código. Precisamente una de las ventajas de un enfoque formal es el ofrecer un marco más apropiado para establecer un proceso de traducción desde una especificación hacia un programa. En este trabajo de Tesis se establecen las bases para animación automática de especificaciones OASIS utilizando como entorno de implementación Programación Lógica Concurrente. El trabajo se orienta a la construcción de un ambiente para validación temprana de especificaciones OASIS mediante animación automática. Agradecimientos Ni el resultado ni el recuerdo de mi dedicación a este trabajo serían los mismos sin la positiva participación directa o indirecta de muchas personas. En especial quisiera agradecer a las siguientes personas: A mi director Isidro Ramos por la confianza depositada en mí y por algunos oportunos golpes en la espalda que han mantenido la motivación. A Pedro Sánchez por ser el socio perfecto con quien he podido mezclar agradablemente la amistad y el trabajo. Difícilmente podría haber disfrutado tanto un jamón y un vino hablando de OASIS. A los miembros de nuestro grupo de investigación, en particular a quienes animan las reuniones de grupo en cuyos debates este trabajo ha encontrado una fuente de inspiración. Índice general 1. Introducción 1.1. Motivación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3. Estructura de la Tesis . . . . . . . . . . . . . . . . . . . . . . . 1 1 2 3 2. Antecedentes 2.1. Contexto del trabajo . . . . . . . . . . . 2.1.1. Ingeniería de requisitos . . . . . 2.1.2. Modelado conceptual orientado a 2.1.3. Métodos formales y OASIS . . . 2.1.4. Validación y verificación . . . . . 2.1.5. Prototipación y animación . . . . 2.1.6. Programación automática . . . . 2.2. Descripción del trabajo de Tesis . . . . . 2.3. Trabajos relacionados . . . . . . . . . . . . . . . . . . objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 8 9 11 13 14 16 18 3. OASIS 3.1. Plantilla o tipo . . . . . . . . . . . . . 3.2. Ciclo de vida de un objeto . . . . . . . 3.3. OASIS expresado en Lógica Dinámica 3.4. Semántica de OASIS . . . . . . . . . . 3.5. Concurrencia en OASIS . . . . . . . . 3.6. Conclusiones del capítulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 24 24 26 28 29 29 4. Perspectiva cliente 4.1. Repetición de disparos en OASIS 2.2 . 4.2. Incorporando la perspectiva cliente . . 4.2.1. Identificación de objetos . . . . 4.2.2. Referencias a cliente y servidor 4.2.3. Acciones . . . . . . . . . . . . . 4.2.4. Control de disparos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 32 34 35 36 38 41 iii iv ÍNDICE GENERAL 4.3. Conclusiones del capítulo . . . . . . . . . . . . . . . . . . . . . 5. Especificaciones de proceso 5.1. Procesos en OASIS 2.2 . . . . . . . . . . . . . . . . . 5.2. Procesos en OASIS 3.0 . . . . . . . . . . . . . . . . . 5.2.1. Procesos como fórmulas en Lógica Dinámica 5.3. Un ejemplo más extenso . . . . . . . . . . . . . . . . 5.4. Aspectos adicionales . . . . . . . . . . . . . . . . . . 5.5. Conclusiones del capítulo . . . . . . . . . . . . . . . . . . . . . 6. Interacción entre objetos 6.1. Comunicación entre objetos en OASIS 2.2 . . . . . . . 6.1.1. Disparos . . . . . . . . . . . . . . . . . . . . . . 6.1.2. Eventos compartidos . . . . . . . . . . . . . . . 6.1.3. Comparación entre OASIS 2.2 y TROLL . . . . 6.2. Un nuevo esquema de comunicación . . . . . . . . . . 6.2.1. Mecanismos de comunicación . . . . . . . . . . 6.2.2. Comentarios adicionales . . . . . . . . . . . . . 6.3. Arquitecturas software en el marco de OASIS . . . . . 6.3.1. Componentes y conectores en OASIS . . . . . . 6.3.2. Un ejemplo aplicando arquitecturas software en 6.4. Conclusiones del capítulo . . . . . . . . . . . . . . . . . . . . . . 47 48 49 54 58 63 66 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . OASIS . . . . . 69 69 69 70 72 75 76 79 80 81 83 85 . . . . . . . . . . . . . . . . . . . . . . . . 7. Un ejemplo en OASIS 3.0 87 8. Un modelo de ejecución para OASIS 8.1. El modelo de ACTORS . . . . . . . . . . . . . . . . . . 8.2. Un modelo abstracto para animación en OASIS . . . . . 8.2.1. Alcance del modelo . . . . . . . . . . . . . . . . . 8.2.2. Aspectos básicos . . . . . . . . . . . . . . . . . . 8.2.3. Concurrencia intra-objeto . . . . . . . . . . . . . 8.2.4. Conflicto entre acciones . . . . . . . . . . . . . . 8.2.5. Clasificación de acciones en el buzón . . . . . . . 8.2.6. Comunicación self . . . . . . . . . . . . . . . . . 8.2.7. Modelando el comportamiento interno del objeto 8.2.8. El modelo de ejecución en funcionamiento . . . . 8.3. Conclusiones del capítulo . . . . . . . . . . . . . . . . . 9. Programación Lógica Concurrente 9.1. Programación Lógica y PLC . . . . 9.2. Comunicación entre procesos . . . 9.3. Objetos y clases en PLC . . . . . . 9.4. Conclusiones del capítulo . . . . . 46 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 . 89 . 92 . 94 . 94 . 95 . 96 . 97 . 99 . 100 . 103 . 104 . . . . 107 109 111 119 124 . . . . ÍNDICE GENERAL 10.PLC y OASIS 10.1. Representando una especificación OASIS en KL1 10.1.1. Clases y objetos . . . . . . . . . . . . . . 10.1.2. Comunicación entre objetos . . . . . . . . 10.1.3. Comportamiento del objeto . . . . . . . . 10.1.4. Creación y destrucción de objetos . . . . 10.1.5. Cambio de estado . . . . . . . . . . . . . 10.1.6. Permisos y prohibiciones . . . . . . . . . . 10.1.7. Obligaciones . . . . . . . . . . . . . . . . 10.2. Conclusiones del capítulo . . . . . . . . . . . . . v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 127 127 128 130 130 132 133 133 135 11.LUNA: Una herramienta basada en OASIS 11.1. Ambiente de especificación incremental y validación 11.2. Repositorio OASIS . . . . . . . . . . . . . . . . . . . 11.3. Entorno gráfico de especificación . . . . . . . . . . . 11.4. Traductor OASIS-PLC . . . . . . . . . . . . . . . . . 11.4.1. Alcance del prototipo generado . . . . . . . . 11.4.2. Plantillas para generación de código KL1 . . 11.5. Entorno de animación . . . . . . . . . . . . . . . . . 11.6. Proceso de especificación y validación . . . . . . . . 11.7. Conclusiones del capítulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 137 139 140 141 144 145 149 151 152 . . . . . . . . . 12.Conclusiones 155 12.1. Trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 12.2. Publicaciones impulsadas por esta Tesis . . . . . . . . . . . . . 157 A. Ejemplos en PARLOG 159 A.1. Pequeña biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . 159 A.2. Sistema de control de nivel . . . . . . . . . . . . . . . . . . . . 166 B. Repositorio OASIS 173 C. Plantillas para generar KL1 C.1. Cláusulas para predicados main y router . . . . . . . . . . . . C.1.1. Ejemplo: Código generado para los predicados main y router en el sistema bancario . . . . . . . . . . . . . . . C.2. Cláusulas por cada clase . . . . . . . . . . . . . . . . . . . . . . C.2.1. Cláusulas para el predicado c_clase . . . . . . . . . . . C.2.2. Cláusulas para el predicado o_clase . . . . . . . . . . . C.2.3. Ejemplo: Código generado para los predicado c_account y o_account en el sistema bancario . . . . . . . . . . . 185 185 D. Una sesion con entrada por lotes 203 188 190 190 193 196 vi ÍNDICE GENERAL Índice de figuras 2.1. Paradigma de programación automática . . . . . . . . . . . . . 2.2. Modelado conceptual basado en OASIS . . . . . . . . . . . . . 14 17 3.1. Relación entre mundos, estados y pasos del objeto. . . . . . . . 28 4.1. 4.2. 4.3. 4.4. Repetición de disparos . . . . . . . . . . . . . . . . Perspectivas cliente y servidor de un objeto. . . . . Parte del ciclo de vida de un objeto de la clase Y. . Parte del ciclo de vida de un objeto de la clase X. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 39 43 45 5.1. 5.2. 5.3. 5.4. 5.5. Grafo de transiciones del proceso P. . . . . . . . . . Representación del proceso en su forma no canónica. Representación del proceso en su forma canónica. . . Grafo de transiciones para la operación CANCEL . . Grafo de transiciones para el protocolo GETCHOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 53 54 60 60 6.1. Disparos en OASIS 2.2 . . . . . . . . . . . . . . . . . . . . 6.2. Interpretación de un disparo como el paso de un mensaje. 6.3. Eventos compartidos en OASIS 2.2 . . . . . . . . . . . . . 6.4. Un protocolo para implementar eventos compartidos. . . . 6.5. Caso de objetos relacionados estructuralmente. . . . . . . 6.6. Caso de objetos no relacionados estructuralmente. . . . . 6.7. Representación del mecanismo action sending. . . . . . . . 6.8. Representación del mecanismo action waiting. . . . . . . . 6.9. Representación del mecanismo action calling. . . . . . . . 6.10. Representación de una interacción call/return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 71 71 73 74 74 76 77 78 80 8.1. Representación de aspectos básicos de un actor . . . . . . . . . 91 8.2. Entornos de programación para ejecución de especificaciones OASIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 8.3. Ciclo de vida de un objeto . . . . . . . . . . . . . . . . . . . . . 95 8.4. Vida de un objeto en OASIS . . . . . . . . . . . . . . . . . . . 101 vii viii ÍNDICE DE FIGURAS 8.5. Ciclo de vida de una instancia de cuenta entre t1 y t5 . . . . . 103 9.1. 9.2. 9.3. 9.4. Se produce una naranja, se consume una. . . . . . . . . . . . . 112 Se produce un número ilimitado de naranjas. . . . . . . . . . . 113 Se producen N naranjas. . . . . . . . . . . . . . . . . . . . . . . 114 El consumidor solicita ilimitadas naranjas, cada vez que se recibe una se pide otra. . . . . . . . . . . . . . . . . . . . . . . . . . . 115 9.5. El consumidor solicita N naranjas. . . . . . . . . . . . . . . . . 116 9.6. Espera usando mensaje incompleto. . . . . . . . . . . . . . . . . 117 9.7. Más de un productor enviando mensajes a un mismo consumidor.118 9.8. Utilizando un merge sin límite de entradas. . . . . . . . . . . . 119 9.9. Diagrama de transición de estados para el proceso clase. . . . 123 9.10. Diagrama de transición de estados para el proceso objeto. . . . 124 10.1. Una situación de ejecución para el ejemplo bancario. . . . . . . 128 10.2. Esquema de comunicación entre objetos . . . . . . . . . . . . . 129 11.1. Ambiente para especificación y validación de especificaciones OASIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 11.2. Entorno Gráfico de Especificación. . . . . . . . . . . . . . . . . 141 11.3. Especificación de una clase. . . . . . . . . . . . . . . . . . . . . 142 11.4. Subentorno para edición de Diagramas de Transición de Estados.143 11.5. Tres aspectos en el código KL1 de un prototipo. . . . . . . . . . 143 11.6. Un ejemplo de los pasos de generación automática . . . . . . . 147 11.7. Primera versión del Entorno de Animación . . . . . . . . . . . 148 11.8. Inicio de la sesión de animación . . . . . . . . . . . . . . . . . . 150 11.9. Construcción de acciones de creación de instancias . . . . . . . 151 11.10.Sesión de animación después de crear tres instancias . . . . . . 152 11.11.Acciones ejecutadas por el objeto account(101) . . . . . . . . 153 11.12.Estado actual del objeto account(101) . . . . . . . . . . . . . 153 A.1. Esquema de comunicación en la pequeña biblioteca . . . . . . . 160 A.2. Esquema del sistema de control de nivel. . . . . . . . . . . . . . 166 A.3. Esquema de implementación en PARLOG para el ejemplo. . . . 166 B.1. B.2. B.3. B.4. B.5. B.6. B.7. B.8. Paquete Paquete Paquete Paquete Paquete Paquete Paquete Paquete “esquema” . . . . . . . . . . . . “clase” . . . . . . . . . . . . . . “interfaz” . . . . . . . . . . . . “atributo e identificador” . . . “servicio, proceso y parámetro” “evaluaciones” . . . . . . . . . “derivaciones” . . . . . . . . . . “precondiciones” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 174 175 175 176 176 177 177 ÍNDICE DE FIGURAS B.9. Paquete B.10.Paquete B.11.Paquete B.12.Paquete B.13.Paquete B.14.Paquete B.15.Paquete B.16.Paquete B.17.Paquete B.18.Paquete “disparos” . . . . “procesos” . . . . “cliente-servidor” “acciones” . . . . “relaciones” . . . “agregacion” . . “herencia” . . . . “fórmula” . . . . “ámbito fórmula” “parámetros” . . ix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 178 179 179 180 180 181 182 182 183 x ÍNDICE DE FIGURAS Capítulo 1 Introducción En este capítulo se presentan la motivación y los objetivos de esta Tesis. Además, se indica la estructura de esta memoria, describiendo brevemente el contenido de los capítulos posteriores. 1.1. Motivación La ingeniería de requisitos [75, 98, 16] es un campo de reconocida importancia en el ámbito teórico y práctico de la ingeniería del software. Las mayores carencias (y desafíos) de la construcción de software se encuentran en las primeras actividades del proceso. En ellas, la principal dificultad radica en la distancia existente entre el espacio del problema (Universo de Discurso) y el espacio de la solución (el software construido). El modelo conceptual establece el vínculo entre ambos expresando los requisitos funcionales del sistema y constituyendo la base para las tareas siguientes en el desarrollo del sistema. La construcción del modelo conceptual del sistema es un proceso de descubrimiento, no sólo para el analista, sino también para el usuario1 . La estrategia que más se ajusta a esta situación es construir el modelo conceptual de forma iterativa, con refinamientos sucesivos y mediante interacción entre el usuario y el analista. En cada paso el analista debe verificar el modelo y validarlo respecto de las necesidades del usuario. Finalmente, una vez alcanzada la conformidad de las partes involucradas, el modelo conceptual se utiliza como entrada para las fases posteriores del desarrollo. El impacto de una modificación en el modelo conceptual, respecto de los resultados de las fases siguientes y del producto final, es por lo general muy grande. Por lo tanto, la validación temprana del modelo conceptual es importante. Las dificultades asociadas a 1 En inglés se utilizaría stakeholder, lo cual resulta más apropiado pues incluye a todos los usuarios directos e indirectos del sistema. 1 2 CAPÍTULO 1. INTRODUCCIÓN la tarea de validación del modelo conceptual constituyen la motivación para desarrollar una propuesta basada en animación automática. Este trabajo de Tesis se ha generado en el grupo de investigación en Modelado Conceptual Orientado a Objetos y Bases de Datos, perteneciente al Departamento de Sistemas Informáticos y Computación de la Universidad Politécnica de Valencia. Una de las principales actividades llevadas a cabo en los últimos años por este grupo ha sido el desarrollo de OASIS (Open and Active Specification of Information Systems) [69, 70, 56], un modelo formal para la construcción de modelos conceptuales que sigue el paradigma orientado a objeto. En la perspectiva de OASIS, un sistema de información es una sociedad de objetos autónomos y concurrentes que interactúan entre sí. En este contexto, el propósito de este trabajo de Tesis ha sido estudiar la generación automática de código que permita animar especificaciones OASIS. Se ha utilizado Programación Lógica Concurrente [85] como lenguaje a ser generado. El programa obtenido automáticamente tiene la particularidad que su ejecución está orientada especialmente a ayudar en la validación de la especificación OASIS asociada. Todas las actividades asociadas al desarrollo de este trabajo se han enmarcado en dos proyectos de la Comisión Interministerial de Ciencia y Tecnología (CICYT): OASIS (1994-1997, TIC94-0557) y MENHIR [63] (19972000, TIC97-0593-C05-01). Este último es un proyecto coordinado en el cual participan además grupos de investigación de las Universidades de Granada, Murcia, Sevilla y Valladolid. 1.2. Objetivos El objetivo global de este trabajo de Tesis es establecer las bases teóricas y prácticas para la animación automática de especificaciones OASIS en un entorno de programación concurrente. Se pretende conseguir una versión preliminar de un ambiente en el cual, partiendo de un modelo conceptual en OASIS, se obtenga de forma automática un prototipo que ayude a la validación de requisitos. Para la implementación del prototipo se ha usado Programación Lógica Concurrente, utilizando los lenguajes PARLOG [12] y KL1 [14]. Los objetivos específicos de esta Tesis son: Extender y completar OASIS 2.2 [70] para que constituya un marco formal apropiado a partir del cual pueda establecerse un trabajo de prototipación2 automática. El trabajo asociado se ha enmarcado dentro del 2 Se usará “prototipación” y sus palabras derivadas para referirse al concepto del inglés prototyping. 1.3. ESTRUCTURA DE LA TESIS 3 desarrollo de una nueva versión de OASIS (versión 3.0) [56] en la cual se incluyen algunos de los resultados obtenidos en esta Tesis. Así, los objetivos siguientes se establecen considerando OASIS 3.0. Establecer un modelo abstracto de ejecución para especificaciones OASIS. Establecer correspondencias entre conceptos OASIS y conceptos de Programación Lógica Concurrente, determinando pautas de traducción. Implementar3 dichas pautas en un programa traductor que genere automáticamente un programa lógico concurrente a partir del repositorio de una especificación OASIS. Construir una versión preliminar de un ambiente para animación automática de especificaciones OASIS y proponer un proceso de ingeniería de requisitos basado en animación automática de modelos conceptuales. 1.3. Estructura de la Tesis La presentación de esta Tesis se ha organizado en los siguientes capítulos: Capítulo 2: Antecedentes Se presenta el contexto del trabajo de Tesis incluyendo una descripción de los aspectos de ingeniería del software involucrados. Además se determina el alcance del trabajo, estableciendo la relación entre los siguientes aspectos: animación automática de especificaciones OASIS, utilización de Programación Lógica Concurrente y validación de especificaciones OASIS. Por último, se analiza el estado del arte comentando algunos trabajos relacionados. Capítulo 3: OASIS Se introduce OASIS 3.0 como lenguaje formal para el modelado conceptual de sistemas de información. En esta Tesis se partió de OASIS versión 2.2 pero muchos de los inconvenientes encontrados y resueltos durante el desarrollo de este trabajo llevaron al establecimiento de OASIS versión 3.0. Así, en este capítulo se ha preferido mostrar la versión 3.0, dejando para los tres capítulos siguientes la discusión y propuestas de cambio relacionadas con animación de especificaciones que fueron incluidas finalmente en la versión 3.0. 3 Se utilizará “implementar” y sus palabras derivadas para referirse al concepto del inglés implement. 4 CAPÍTULO 1. INTRODUCCIÓN Capítulo 4: Perspectiva cliente En este capítulo se describen algunos inconvenientes de OASIS 2.2 ocasionados por no contar con la capacidad para expresar adecuadamente la perspectiva cliente de un objeto. Se plantea una forma homogénea de incorporar este aspecto. Utilizando un nuevo concepto de acción, tanto los servicios provistos como los requeridos por un objeto son acontecimientos relevantes en su vida. Para OASIS, la incorporación de la perspectiva cliente representa una mejora en expresividad. En particular, para la animación de especificaciones OASIS esto permitió disponer de un mecanismo para controlar la repetición de un disparo. Capítulo 5: Especificaciones de proceso En OASIS 2.2 se dispone de dos formas para especificar el comportamiento: basándose en el estado del objeto o basándose en secuencias acontecidas de acciones. En cada caso se utiliza una formalización distinta; para el primer caso se usa una variante de Lógica Dinámica (que incluye la representación de los operadores deónticos de obligación, prohibición y permiso), para el segundo se usa un Álgebra de Procesos para Objetos. La integración de estas dos visiones del comportamiento con el propósito de animación significaba eludir un gran obstáculo. En este capítulo se establece un nuevo enfoque para la especificación de procesos, basado también en un Álgebra de Procesos y que permite una interpretación directa y sencilla en la variante de Lógica Dinámica utilizada. Así, en términos de animación, todo el comportamiento de un objeto está determinado por un conjunto de fórmulas en Lógica Dinámica. Esto simplifica el establecimiento de correspondencias entre OASIS y el entorno de implementación. Capítulo 6: Interacción entre objetos La incorporación de la perspectiva cliente y de otros aspectos creó la necesidad de revisar los mecanismos de comunicación ofrecidos por OASIS 2.2. En este capítulo se describe la interacción entre objetos en OASIS 2.2 y se hace una comparación con TROLL (uno de los lenguajes de especificación más próximos a OASIS). Se propone un nuevo esquema de interacción entre objetos, el cual finalmente ha sido incluido en OASIS 3.0. Adicionalmente, se analiza la posibilidad de introducir en el futuro la filosofía de Arquitecturas Software. 1.3. ESTRUCTURA DE LA TESIS Capítulo 7: Un ejemplo en OASIS 3.0 Se presenta un ejemplo simple pero que incluye la funcionalidad cubierta por la versión actual del traductor OASIS-KL1. Este ejemplo será utilizado en los capítulos posteriores. Capítulo 8: Modelo de ejecución Se establece un modelo abstracto de ejecución para especificaciones OASIS 3.0. Este modelo de ejecución provee una interpretación operacional para especificaciones OASIS, incluyendo el tratamiento de la concurrencia. Capítulo 9: Programación Lógica Concurrente Se presenta el paradigma de Programación Lógica Concurrente el cual será utilizado como entorno de implementación para la animación de especificaciones OASIS. Se describen las principales características de un lenguaje lógico concurrente. Particularmente se presenta la comunicación entre procesos provista y cómo se pueden modelar objetos y clases. Además, se analizan varios ejemplos desarrollados usando el lenguaje PARLOG. Capítulo 10: OASIS y Programación Lógica Concurrente En este capítulo se establecen correspondencias entre conceptos de OASIS y elementos de la Programación Lógica Concurrente. Mediante un ejemplo implementado en el lenguaje KL1 se ilustra cómo los conceptos OASIS tienen una representación directa en un programa lógico concurrente. Capítulo 11: LUNA: Una herramienta basada en OASIS Se presenta un ambiente para la especificación y validación de requisitos llamado LUNA. Se trata de un workbench compuesto por tres herramientas, un repositorio OASIS y un traductor OASISKL1. Las herramientas son: asistente para construir escenarios, entorno gráfico de especificación y entorno gráfico de animación. Capítulo 12: Conclusiones Se resumen los principales resultados y aportes de esta Tesis. Se plantean las líneas de continuación que sería interesante abordar para consolidar y extender el trabajo realizado. 5 6 CAPÍTULO 1. INTRODUCCIÓN Apéndice A: Ejemplos en PARLOG Se presentan dos ejemplos más extensos que ilustran algunos aspectos de la representación de clases y objetos en Programación Lógica Concurrente. Apéndice B: Repositorio OASIS Se describe la estructura del repositorio utilizado para almacenar especificaciones OASIS. Apéndice C: Plantillas para generar KL1 En este apéndice se muestran algunas plantillas utilizadas para construir el traductor OASIS-KL1. Además se incluye parte del código generado para el ejemplo del capítulo 7. Apéndice D. Una sesión con entrada por lotes Se muestra una sesión de animación en la cual todas las acciones son leídas desde un fichero y el entorno de animación genera otro fichero con los resultados, incluyendo para cada objeto la secuencia de acciones acontecidas y los correspondientes estados alcanzados. Capítulo 2 Antecedentes En este capítulo se describe el contexto en el cual se desenvuelve esta Tesis, permitiendo enmarcar adecuadamente el trabajo desarrollado y establecer su alcance. Adicionalmente se analizan de algunos trabajos relacionados ilustrando el estado del arte en dicho contexto. 2.1. Contexto del trabajo En este trabajo se conjugan varios aspectos de la ingeniería del software. A continuación se hará una breve descripción de cada uno de ellos. Aunque existen relaciones de dependencia y solape entre dichos aspectos, su presentación se orientará a una caracterización más o menos independiente que permita en la sección siguiente precisar el trabajo desarrollado y los aportes que se esperan conseguir. 2.1.1. Ingeniería de requisitos “Ingeniería de requisitos es el proceso para establecer los servicios que el sistema debería proveer y las restricciones bajo las cuales debe operar” [91]. En general dichos servicios y restricciones se denominan requisitos. Un requisito funcional es aquel que describe un servicio o función del sistema, en cambio, un requisito no-funcional es una restricción impuesta sobre el sistema o el proceso de desarrollo. Algunos problemas que afectan el éxito del proceso de ingeniería de requisitos son [17, 45]: Es potencialmente imposible definir un conjunto completo de requisitos. Se puede expresar con precisión un requisito conocido, pero no existe un método que nos diga qué debería ser especificado. 7 8 CAPÍTULO 2. ANTECEDENTES Es difícil obtener un conjunto consistente de requisitos. En sistemas grandes hay diversidad de usuarios, conflicto entre restricciones organizacionales y de presupuesto con respecto a necesidades de usuarios finales. Los requisitos evolucionan constantemente, incluso durante el desarrollo del sistema. No existen métodos satisfactorios para abordar esta fase y consecuentemente las herramientas disponibles no ofrecen una adecuada integración de técnicas1 . Las barreras de comunicación entre los colectivos involucrados suelen ser un gran problema. Los requisitos pueden establecerse en tres niveles de abstracción [94]: requisitos organizacionales (relacionando al sistema con los objetivos y restricciones del negocio), requisitos del dominio del problema (describiendo el sistema en términos de las interacciones con su entorno) y requisitos del sistema (estableciendo la estructura y el comportamiento interno del sistema). En este aspecto, nuestro interés se centra principalmente en el modelado de requisitos del sistema. 2.1.2. Modelado conceptual orientado a objeto Un modelo conceptual de un sistema de información representa los requisitos del sistema, esencialmente los requisitos fincionales. El término conceptual se refiere al hecho que el modelo consiste en conceptos mediante los cuales el usuario y el analista interpretan y observan el espacio del problema. El modelado conceptual tiene sus raíces en el modelado semántico de datos [92, 86, 40, 29]. Cuando se utiliza el enfoque orientado a objeto para el modelado conceptual los requisitos funcionales son encapsulados bajo el concepto de objeto, incluyendo las perspectivas estática y dinámica del sistema estudiado. Durante la fase de modelado conceptual se llevan a cabo esencialmente cuatro tareas [20]: 1. Captura de requisitos: descubrir lo que el usuario quiere obtener como sistema. 2. Modelado: describir el modelo conceptual del sistema. 1 En este aspecto la comunidad formada por quienes trabajamos en desarrollo de software es una de las principales culpables. Frecuentemente los métodos y técnicas son reemplazados considerándolos obsoletos sin llegar a consolidarse, aunque normalmente no se cuenta con la suficiente evidencia de que dicho reemplazo es la alternativa más recomendable. 2.1. CONTEXTO DEL TRABAJO 9 3. Análisis: verificar que el modelo satisface ciertos criterios de calidad y consistencia. 4. Validación: determinar si el modelo conceptual reúne los requisitos informales obtenidos del usuario. Estas tareas se repiten hasta que en 4) se obtiene la conformidad del modelo conceptual respecto de los requisitos informales del usuario. En la actualidad el uso de escenarios [80] para capturar requisitos ha despertado gran interés, prueba de ello es la actividad impulsada por el proyecto ESPRIT llamado CREWS2 (C ooperative Requirements Engineering with Scenarios). Un escenario es una descripción parcial del comportamiento de un sistema y su ambiente en una determinada situación. Los escenarios describen partes posiblemente solapadas del comportamiento de un sistema. Además de ser útiles en la captura de requisitos, los escenarios constituyen un tipo de casos de prueba, particularmente interesante para la validación del sistema. Las técnicas para establecer escenarios, en cuanto a detalle y rigor varían desde descripciones narrativas hasta representaciones basadas en notaciones formales. 2.1.3. Métodos formales y OASIS Una manera de ayudar en la construcción de software más fiable es utilizar métodos formales [99, 66, 60, 27]. Los métodos formales ofrecen para el desarrollo de software una mejora en la calidad del producto y reducción de costos de construcción y mantenimiento. Sin embargo, la introducción de métodos formales no ha sido inmediata y sólo en la actualidad comienzan tímidamente a ser introducidos en el entorno industrial de desarrollo de software [15, 94]. Cuatro razones explican esta situación [39]: falsas expectativas o desconocimiento, carencia de estándares para métodos y su aplicación, falta de herramientas integradas en entornos CASE3 y finalmente precaria preparación entre sus usuarios potenciales. La verificación y validación del modelo conceptual exigen disponer de algún formalismo preciso y a la vez con la suficiente capacidad expresiva, necesaria para capturar los aspectos de interés del problema. En la práctica, los requisitos del usuario son representados mayoritariamente usando modelos semiformales, incluidos en los enfoques más populares en la actualidad, entre ellos los métodos no orientados a objeto [41, 101] y los orientados a objeto [81, 10, 42, 62, 87, 31]. Notacionalmente los métodos orientados a objeto más conocidos han sido integrados en el Unified Modeling Languaje (UML) [78]. 2 3 http://sunsite.informatik.rwth-aachen.de/CREWS/ Computer Aided Software Engineering. 10 CAPÍTULO 2. ANTECEDENTES OASIS es un enfoque orientado a objeto y formal para la especificación de modelos conceptuales de sistemas de información. En OASIS un sistema de información es visto como una sociedad de objetos autónomos y concurrentes que se comunican entre sí a través de acciones. OASIS en su primera versión [69] fue formalizado a través de Teorías de Primer Orden que evolucionan con el tiempo. Este enfoque lo situó históricamente en un entorno de Programación Lógica complementado con un monitor para la gestión de la perspectiva dinámica del sistema. A partir de la segunda versión [70] se cambió de marco formal y se trabajó en el contexto de una variante de Lógica Dinámica [30] que permite representar los operadores de obligación, prohibición y permiso usados en Lógica Deóntica [2]. En este marco, OASIS tiene una base formal más adecuada desde el punto de vista de su comprensión, manteniendo sus buenas propiedades. Otros enfoques formales con una motivación similar a la de OASIS son: TROLL [43], LCM [22], ALBERT [19], OBLOG [67] y TESORO [93]. Sin entrar en detalles de comparación, sólo se destacará que a diferencia de otros enfoques formales, en OASIS desde sus primeras versiones se ha puesto especial interés en tres aspectos esenciales que facilitan su integración en entornos industriales de desarrollo de software: Construcción de herramientas que soporten el proceso de modelado conceptual. Se ha construido un entorno CASE basado en la versión precedente de OASIS y adaptado a OO-METHOD [71]. Establecimiento de un método de desarrollo basado en OASIS, llamado OO-METHOD [72]. Generación automática de código a partir de especificaciones OASIS, orientada tanto a la validación (interés de esta Tesis) como a la construcción del producto final [73]. Por otra parte, si se compara el procedimiento seguido por las propuestas semiformales para modelado orientado a objeto más populares respecto del enfoque que se ha seguido en el desarrollo de OASIS, se puede observar que son contrapuestos. En OASIS un aspecto importante ha sido el reducir la notación y técnicas a un conjunto pequeño y coherente, con la suficiente expresividad y con un significado preciso, evitando así problemas de “interferencia semántica” [67] entre los diferentes aspectos del lenguaje. Esta estrategia es opuesta a la seguida en el desarrollo de UML, en el cual se han fundido varias notaciones para posteriormente intentar establecer una interpretación y un método de aplicación globales. En el caso de OASIS, después de establecer los conceptos fundamentales es relativamente sencillo establecer una notación o buscar alguna entre las notaciones existentes y adaptarla, incluso se puede utilizar parte de la notación de UML. 2.1. CONTEXTO DEL TRABAJO 2.1.4. 11 Validación y verificación La noción de corrección para el software está inherentemente limitada. Para abordar un sistema basado en computador debe comprenderse su hardware, software y entorno, y cómo ellos interactúan. En la medida que los sistemas de información a desarrollar son más complejos han quedado en evidencia las deficiencias en su proceso de construcción. En particular es reconocida la dificultad para verificar sistemas concurrentes y/o distribuidos. Cada vez existe mayor preocupación respecto de los posibles daños por errores en sistemas de información, más aún cuando se trata de posibles problemas para las personas (safety critical systems). Estos factores de complejidad se presentan frecuentemente en sistemas de tiempo real y/o empotrados. Se trata pues de una cuestión de confiabilidad asociada a la calidad del producto software construido. La validación y verificación del producto desempeñan un papel esencial para asegurar la calidad del software. La validación y verificación (V & V) son las tareas encargadas de asegurar la calidad del producto de software y se definen como [9]: Validación: ¿Estamos construyendo el producto correcto?, es decir, comprobar que el sistema reúne las expectativas del usuario. Verificación: ¿Estamos construyendo correctamente el producto?, es decir, comprobar que el sistema satisface su especificación. Si la validación y verificación no son las adecuadas, los errores en los requisitos se propagarán hacia las fases posteriores. El costo de modificar un sistema debido a un error en los requisitos es mucho mayor que el costo de reparar un error de programación, puesto que existe un efecto de amplificación del impacto del error al pasar de una fase a otra. Así, mientras más tarde se corrija un error más costoso resulta repararlo. Las técnicas para validación y verificación pueden clasificarse en [91]: Técnicas estáticas: se centran en el análisis y comprobación de la representación del sistema, incluyendo documentos, diagramas y código. Técnicas dinámicas: implican ejecutar algún tipo de implementación del sistema. Podría parecer que sólo con las técnicas estáticas es suficiente pero esto no tiene sentido puesto que las técnicas estáticas se orientan más bien a la verificación, no pueden demostrar que el sistema satisface las expectativas del usuario (validación). En este trabajo de Tesis el interés es utilizar técnicas dinámicas para la validación del modelo conceptual. 12 CAPÍTULO 2. ANTECEDENTES La prototipación y las pruebas de programas son técnicas dinámicas. En ambos casos es importante tener presente la célebre frase de W. Dijkstra: “las pruebas pueden demostrar la presencia de errores pero no su ausencia”. En prototipación normalmente se cuenta con una implementación parcial (en algún sentido) del sistema, en cambio las pruebas del programa se realizan sobre todo o parte del producto ya construido. Las pruebas de programa son útiles principalmente para la verificación del sistema. Dentro de los diferentes tipos de pruebas, las pruebas de aceptación (pruebas alfa) y las pruebas beta son las que más información aportan para la validación del sistema. A continuación se presenta una clasificación de técnicas específicas para la validación de modelos conceptuales [21]: Técnicas de conversión: presentan el modelo conceptual en una forma más fácil de comprender por el usuario. Técnicas de comportamiento: presentan una ejecución de la especificación, lo que permite en un sentido amplio observar y experimentar propiedades de la especificación. La prototipación se incluye en este grupo. Técnicas de análisis: se basan en el estudio de trazas posibles obtenidas de la especificación y contrastadas con el comportamiento esperado. Para obtener trazas de la especificación puede utilizarse una técnica de comportamiento. En cualquier técnica de validación es necesario contrastar en algún sentido la especificación con los requisitos informales del usuario. Lo más inmediato es incluir al usuario en el proceso de validación y utilizar técnicas de conversión junto con técnicas de comportamiento. Sin embargo, este enfoque no aprovecha necesariamente el trabajo previo a la construcción del modelo, es decir, lo realizado durante la captura de requisitos. El problema principal es que la captura de requisitos es una tarea muy informal. En este sentido, la utilización de una técnica de escenarios para la captura de requisitos puede ayudar en la validación del modelo conceptual. Se trata de comprobar que el modelo al menos tiene la funcionalidad establecida por el conjunto de escenarios. Este enfoque podría enmarcarse dentro de las técnicas de análisis. Para poder efectuar dicha comprobación es necesario que los escenarios y el modelo conceptual sean comparables en algún sentido. De todas formas, es importante considerar que el conjunto de escenarios puede que no represente por completo a los requisitos del sistema. 2.1. CONTEXTO DEL TRABAJO 2.1.5. 13 Prototipación y animación Las dificultades encontradas para validar con mayor precisión el modelo conceptual del sistema han impulsado la utilización de técnicas de prototipación. La existencia de errores y omisiones constituye un riesgo significativo en el modelado conceptual. Los objetivos de un prototipo pueden ser: determinar las interfaces, validar los requisitos funcionales y/o demostrar la factibilidad del sistema. Un argumento común contra la prototipación es su costo, el cual puede ser considerable. Normalmente, el prototipo exhibe sólo algunos aspectos del sistema, dejando de lado otros como eficiencia, seguridad, confiabilidad, etc. Un prototipo puede orientarse a ilustrar detalles de ciertas partes de la funcionalidad total (propotipado vertical) o mostrar toda la funcionalidad sin llegar a implementar funciones específicas (prototipado horizontal). En la práctica ambos enfoques se mezclan. Por otra parte, los prototipos pueden clasificarse en prototipos desechables y prototipos evolutivos. El objetivo de un prototipo desechable es capturar y validar los requisitos del usuario, una vez cumplido este propósito el prototipo es desechado. En este caso el prototipo es construido desde una especificación obtenida experimentalmente y modificada hasta obtener la conformidad del usuario. Con un prototipo evolutivo se pretende llegar a la versión definitiva del producto mediante refinamientos sucesivos. Algunas herramientas para construcción de prototipos son: lenguajes de especificación ejecutables, lenguaje de muy alto nivel y generadores de aplicaciones en lenguajes de cuarta generación. La utilización de un lenguaje de especificación ejecutable y formal resulta particularmente atractiva pues combina una especificación no ambigua con prototipación, sin haber costos adicionales una vez que la especificación ha sido escrita. La prototipación de una especificación orientada a la validación de requisitos, se denomina “animación” [33, 21, 89]. Desde el punto de vista de la validación de requisitos, con un prototipo podrían realizarse dos formas de validación: “validación dirigida” y “validación exploratoria”. La validación dirigida utiliza el prototipo para recrear cada uno de los escenarios establecidos. La validación exploratoria intenta descubrir un comportamiento no deseable mediante simple interacción con el prototipo. La prototipación tradicional permite sólo validación exploratoria pues generalmente el prototipo provee la interfaz del producto final, sin ofrecerse mecanismos que permitan concentrarse en acciones acontecidas o facilitar la observación del estado de los objetos. Para efectuar adecuadamente una validación dirigida es conveniente disponer de un entorno de animación que interactúe con el prototipo ofreciendo al analista una interfaz estándar y específicamente diseñada para ayudar en este tipo de validación. 14 2.1.6. CAPÍTULO 2. ANTECEDENTES Programación automática El paradigma de programación automática enunciado por Balzer [3, 4] parece estar en su apogeo, aunque no siempre basado en métodos formales, como se propuso originalmente, sino más bien en métodos semiformales. La generación automática de código a partir de especificaciones (preferentemente gráficas) es un tema actual de gran interés en ingeniería de software. La automatización de las fases del desarrollo ha determinado una tendencia histórica en la evolución del proceso de desarrollo de software, según la cual actividades realizadas inicialmente de manera informal son mas tarde formalizadas y finalmente automatizadas (con poca o ninguna intervención del desarrollador) [16]. La generación de código a partir de modelos conceptuales no es más que la continuación de dicha tendencia. El desarrollo de software se concentra cada vez más en la parte más creativa e irreemplazable (no automatizable completamente) del proceso, es decir, el análisis y la especificación del sistema. Para la mayoría de los métodos semiformales se han construido entornos CASE que permiten llevar a la práctica su perspectiva de ingeniería del software. En ellos, la posibilidad de conseguir automáticamente código ejecutable es una característica muy valorada. El resultado conseguido va desde plantillas de código y definiciones de bases de datos hasta aplicaciones completas incluyendo el código compilado y la creación de la base de datos [79, 76]. Sin embargo, el software obtenido sigue padeciendo los mismos defectos asociados al proceso de desarrollo sin automatización. La razón es que en la mayoría de los casos la manera de construir los sistemas no se cambia, sólo se automatizan técnicas y procedimientos cuyo rigor es cuestionable. Desiciones Especificación Informal Especificación Especificación de alto nivel (prototipo) Desarrollo Formal Tranformación Interactiva Especificación de bajo nivel Transformación Automática Código Fuente Optimización Validación de Especificación Mantenimiento Figura 2.1: Paradigma de programación automática La Figura 2.1 (extraída desde [4]) ilustra un paradigma ideal de programación automática. Se distinguen dos fases globales: especificación (incluyendo 2.1. CONTEXTO DEL TRABAJO 15 validación) y transformación. Las características principales de este paradigma son: la especificación es formal y ejecutable (constituye el primer prototipo del sistema), la especificación es validada mediante prototipación, a través de transformaciones formales la especificación se convierte en la implementación del sistema, en el último paso de transformación se obtiene una implementación en un lenguaje de programación determinado, las pruebas que verifican la correspondencia con la especificación no son necesarias, el mantenimiento se realiza sobre la especificación (no sobre el código fuente), la documentación es generada automáticamente y el mantenimiento es realizado por repetición del proceso (no mediante parches sobre la implementación). La capacidad de ejecución de una especificación ha sido tema de debate, contando con simpatizantes [24] y detractores [35]. Una de los aspectos más cuestionados es la conveniencia de eliminar la mítica frontera entre especificar el “qué” y el “cómo” [88] que históricamente ha diferenciado análisis respecto del diseño del sistema. Una especificación ejecutable tiene inevitablemente que incorporar ciertos aspectos asociados comúnmente a decisiones de diseño. Sin embargo, la falta de ejecutabilidad hace que una especificación de análisis requiera mucho trabajo para convertirla en una especificación de diseño. En este sentido, el paradigma propuesto por Balzer es conciliador de ambas posturas pues está basado en transformaciones sucesivas de la especificación hasta obtener una implementación definitiva. Inicialmente la especificación es informal y no ejecutable, a continuación pasa a ser formal y ejecutable, posteriormente mediante refinamientos formales sucesivos llega a ser el producto final, manteniendo la equivalencia semánticamente respecto de la especificación original. En [5] se hace una clasificación del estado actual en generación automática de código a partir de modelos, estableciendo tres enfoques: estructural, de comportamiento y de traducción. En el enfoque estructural la generación de código es incompleta y se centra en los aspectos de estructura del código. Este enfoque es el que más se ajusta a la mayoría de las metodologías orientadas a objeto en las cuales se hace un desarrollo incremental pasando en forma gradual desde análisis a diseño y posteriormente a código. El enfoque de comportamiento se basa en añadir especificaciones de acciones a los diagramas de transición de estado, lo cual asociado a los modelos de objetos y de comunicación permite generar código que puede ser ejecutado. Sin embargo, el código generado no suele ser la versión definitiva. El enfoque de traducción está basado en establecer un modelo de aplicación y uno de arquitectura, ambos independientes. El modelo de la aplicación determina para los objetos su estructura, comportamiento y comunicación. El modelo de arquitectura es un conjunto de reglas que traducen los constructores del modelo de aplicación en código fuente considerando aspectos específicos del entorno de implementación. El enfoque de traducción es el que incluye mayor grado 16 CAPÍTULO 2. ANTECEDENTES de automatización. Sin embargo, no es sencillo definir un modelo de arquitectura específico, existen muchos factores en un entorno de implementación que hacen necesario combinar conocimientos técnicos de diversas áreas (lenguajes de programación, sistemas operativos, redes, etc.). 2.2. Descripción del trabajo de Tesis De acuerdo con lo presentado en la sección anterior, este trabajo de Tesis se sitúa en un marco que combina lo siguiente: Utilización de OASIS como enfoque formal para el modelado conceptual orientado a objeto. Animación automática de especificaciones OASIS. A partir de una especificación OASIS se obtiene automáticamente un prototipo del sistema, orientado exclusivamente a la validación del modelo conceptual. Es decir, se aborda sólo la primera fase del paradigma de programación automática de Balzer. Captura de requisitos usando alguna técnica de escenarios con el propósito de facilitar la comparación de los requisitos respecto del comportamiento exhibido por el prototipo. Técnicas para la validación de modelos conceptuales, en particular se trabajará con una técnica que según las clasificaciones mencionadas se cataloga, por una parte como técnica dinámica y por otra, como una técnica tanto de comportamiento como de análisis. La Figura 2.2 ilustra un proceso de modelado conceptual en OASIS, orientado a la validación mediante animación de un prototipo generado automáticamente. En la captura de requisitos se considera la utilización de alguna técnica para representación de escenarios. El analista extrae desde conjunto de escenarios los elementos de especificación que conformarán la especificación de requisitos. En este aspecto, es importante destacar que el determinar un comportamiento general a partir de ejemplos no es una tarea sencilla y la calidad del resultado depende de la capacidad del analista. Para la representación del modelo conceptual se utilizan técnicas principalmente gráficas que guardan una correspondencia directa con elementos de una especificación OASIS. Así, para el analista resulta implícita la utilización de OASIS, más aún si se utiliza una notación gráfica basada, por ejemplo en UML y utilizando sólo los elementos de UML que sean útiles desde el punto de vista de OASIS. La verificación de consistencia del modelo conceptual consiste en comprobar las restricciones del modelo OASIS. Gracias a utilizar un modelo formal es posible realizar una 2.2. DESCRIPCIÓN DEL TRABAJO DE TESIS Validación mediante animación Captura de requisitos ? 17 Escenarios Análisis y Especificación Mapade revisón de gestión ISO 9001:1994 Claúsula 4.1 {Jefe deplanta} Verificación de consistencia EtQ9000Maps Mapas de referencia: 1 Prepararel orden del día Acción correctiva 2 {Secretaria} Usuario Registros Distribuir el orden del de calidad día al equipo de revisión de gestión Definiciones: Indicador- Una medida cuantitativa del funcionamiento de un proceso de sistema de calidad. 3 CAR - Solicitud de acción correctiva {Equipo de revisión de gestión} Revisar las actas de las reuniones anteriores para resolver la CAR Objetivo- Objetivo cuantitativopara un proceso de sistema de calidad. {Jefe de planta} 5 {Equipo de revisión de gestión} 4 ¿Requisito Sí Designa personal pararesolver el Requisitos: Indicadores del sistema de calidad: Los ejemplos incluyen: - Pasos en la obtención de la Certificación de calidad o formulación de la misión requisito anterior de la CAR anterior? - Demanda de calidad - Resumen del material no apto - Resumen de las quejas del consumidor No {Equipo de revisión de gestión} 6 7 Revisa los - Resumen de la auditoría interna - Resumen de las existencias de material - Entregaa tiempo - Resumen de la acción correctiva Registra elementos del requisito anterior indicadores del sistema de calidad y nombramientos en lasactas de la reunión vs.objetivos Traducción automática Mapasasociados: {Secretaria} Ninguno 9 {Equipo de revisión de gestión} 8 ¿Indicadores en objetivo? No {Equipode revisión de gestión} Da prioridad a los indicadores fuera del objetivo Sí 10 12 {Secretaria} Elabora (CAR)basado Hace constar los {Jefe de calidad} en las prioridades y recursos por mapa de indicadoresobjetivo en las actas de la reunión acción correctiva 13 Dos veces al año, hace {Secretaria} 11 constar la conclusión de efectividad del sistema de calidad en lasactas de a l Hace constar los {Secretaria} indicadores fuera del objetivo y reunión nombramientos en las actas de lareunión Ayuda/Acerca de EtQ 9000 Maps A Correspondencia implícita A {Equipode revisión de gestión} 15 14 {Directorde planta} ¿Resultaadecuada la frecuencia de reuniones para la No Establecer nueva frecuencia revisión de gestión? Sí 16 {Equipo de revisión de gestión} Acordar lafecha y el orden del día de la próximareunión 17 {Secretaria} Elaborar/distribuir actas dela reunión 18 {Secretaria} Archivar lasactas de la reunión por mapa de registrosde calidad Requisitos Modelo OASIS Prototipo para animación Figura 2.2: Modelado conceptual basado en OASIS verificación exhaustiva del modelo mediante técnicas estáticas. Mediante un traductor, a partir del modelo conceptual OASIS se genera un prototipo orientado a la validación del modelo conceptual. El prototipo está codificado en un lenguaje concurrente y con una base formal. El analista puede interactuar directa o indirectamente (por lotes) con el prototipo, introduciendo y observando las acciones acontecidas y los estados alcanzados por los objetos del sistema. La actividad de validación es llevada a cabo contrastando el comportamiento esperado del prototipo (determinado por el conjunto de escenarios) respecto del comportamiento exhibido por la animación de la especificación. Es importante que la representación de escenarios se aproxime a una descripción de trazas de acciones y estados alcanzados, de esta forma el analista tendrá que realizar menos esfuerzo para validar el comportamiento del prototipo respecto del conjunto de escenarios. Si existe una compatibilidad adecuada entre ambas representaciones se puede establecer un apoyo automatizado para dicha comparación. La propuesta descrita tiene las particularidades siguientes: El usuario no interviene directamente en la validación. El analista de forma manual o con asistencia automática procede a la comparación de los escenarios utilizando el prototipo. Sin embargo, no se descarta la utilización de otras técnicas de validación, incluyendo por ejemplo prototipos orientados a la definición de las interfaces del sistema o técnicas de conversión. 18 CAPÍTULO 2. ANTECEDENTES Pueden realizarse dos formas de validación: “validación dirigida” y “validación exploratoria” (ambas descritas anteriormente). La validación podría comenzar apenas se disponga de una versión del modelo conceptual. Para la generación automática sólo debe verificarse que el modelo conceptual sea consistente y completo (al menos de acuerdo con lo mínimo establecido para efectuar la generación automática del prototipo). Del mismo modo, el modelo podría ser validado por partes, generando prototipos para cada parte. El prototipo es generado en un lenguaje que ofrece la posibilidad de justificar las correspondencias entre el modelo conceptual y el prototipo generado, es decir, es posible determinar en algún grado la equivalencia funcional del prototipo respecto de la especificación OASIS. En este sentido, gracias a utilizar un lenguaje concurrente en la implementación es posible prescindir de la incorporación de un monitor que controle la actividad de los objetos y obscurezca las correspondencias entre el modelo conceptual y el prototipo. Usando como marco de referencia el contexto planteado, el alcance de esta Tesis se resume en el siguiente párrafo: Se han establecido las bases teóricas y prácticas para la animación automática de especificaciones OASIS en un entorno de programación concurrente. Se ha construido una versión preliminar de un ambiente en el cual, a partir de un modelo conceptual en OASIS, se obtiene de forma automática un prototipo que ayuda a la validación de requisitos. Para la implementación del prototipo se ha utilizado Programación Lógica Concurrente. 2.3. Trabajos relacionados La mayoría de las herramientas CASE comerciales4 incluyen en alguna medida generación automática de código, principalmente en lenguajes imperativos y en especial C++. Resulta difícil establecer con precisión la calidad del código generado automáticamente sin probar la herramienta. Como suele suceder, existe una notable diferencia entre la información ofrecida por el proveedor y las verdaderas cualidades de la herramienta. Además, por ser un tema candente, las frecuentes nuevas versiones de las herramientas dejan obsoleta cualquier comparación. Sin embargo, tomando como referencia la experiencia del autor en el uso de algunas herramientas CASE y mediante una tarea de búsqueda en la Web, a continuación se presentan algunos comentarios 4 http://www.incose.org/tools/toolsbyname.html y http://www.qucis.queensu.ca/Software-Engineering/tools.html 2.3. TRABAJOS RELACIONADOS 19 que reflejan el estado del arte desde la perspectiva de los propuestas existentes en el ámbito académico y comercial. Rational Rose de Rational5 (en la que participan Booch, Jacobson y Rumbaugh) genera plantillas de código muy elementales (siguiendo el enfoque estructural para la generación de código). Dos herramientas que usan el enfoque de comportamiento para generación de código son: Rhapsody de I-Logix6 (relacionada con Harel) y ObjecTime7 (incluye ROOM, Real-Time Object-Oriented Method). En estas herramientas es posible obtener prototipos ejecutables a partir de los modelos establecidos. Varias herramientas proveen un lenguaje de scripts mediante el cual se puede adaptar la generación de código a distintos estilos y arquitecturas de programación para una determinada configuración hardware-software (coincidiendo así con el enfoque de traducción para la generación de código). Así el grado de automatización conseguido depende de la calidad del script utilizado. Este es el caso de System Architect de Popkin Software & Systems8 que trae predefinido un conjunto de scripts muy rudimentarios para generar código en varios lenguajes, pero que tienen que ser modificados en gran medida para obtener un resultado útil. En OBLOG9 se dispone de un editor de reglas de traducción, sin embargo, el lenguaje utilizado no resulta muy amigable. En BridgePoint de Project Techonology Inc.10 (relacionada con Shlaer y Mellor y su propuesta metodológica) se ofrece como módulo adicional un conjunto de arquitecturas (llamadas model compilers que incluyen reglas de traducción y librerías) específicas para distintos entornos y usadas como entrada para el proceso de generación de código. Un enfoque similar utiliza OO-METHOD CASE, en el cual la traducción se orienta hacia un producto final considerando una determinada arquitectura, pero sin posibilidades de ser modificada por el usuario de la herramienta. Por otra parte, y centrándose exclusivamente en la validación de requisitos mediante animación de la especificación, pocas herramientas proporcionan una ayuda de este tipo. Aunque algunas herramientas son capaces de generar un prototipo ejecutable normalmente no se ofrecen facilidades específicas para la validación utilizando dicho prototipo. La razón es que en la mayoría de los casos el objetivo perseguido es la generación del producto final, con lo cual el prototipo no está pensado para facilitar la validación de requisitos. Una excepción la constituyen algunas herramientas cuyo ámbito de aplicación incluye sistemas de tiempo real y sistemas empotrados. Entre ellas se puede incluir a Rhap5 http://www.rational.com http://www.ilogix.com 7 http://www.objectime.com 8 http://www.popkin.com 9 http://www.oblog.pt 10 http://www.projtech.com 6 20 CAPÍTULO 2. ANTECEDENTES sody, ObjecTime y BridgePoint (en OBLOG existe un módulo de animación pero aún no está comercialmente disponible). En Rhapsody y ObjecTime (y en OBLOG, pero aún en construcción) se incorpora una representación gráfica en diagrama de secuencia en el cual se representan escenarios como secuencias de las interacciones entre objetos a través del tiempo. En este sentido, Aonix11 proporciona un módulo llamado “Validator” que incorpora edición, ejecución y evaluación de escenarios. En estos productos el proceso de validación se dirige a contrastar trazas obtenidas por ejecución del prototipo. En ObjecTime se provee de un procedimiento para contrastar automáticamente escenarios así especificados. En BridgePoint la validación se realiza monitoreando el prototipo en distintos niveles (acción, sentencia y componente) pero es difícil determinar variaciones respecto al comportamiento esperado pues la interfaz y el enfoque seguido se acercan más a la funcionalidad de un depurador de código fuente. Estas propuestas presentan el inconveniente de estar basadas en modelos donde el comportamiento es especificado de forma imperativa con lo cual la validación debe establecerse en un nivel de abstracción bastante más bajo que el presente en el espacio del problema. El caso de OBLOG podría ser una excepción puesto que se originó en un contexto formal y declarativo, sin embargo, no se ha contado con información para poder constatar si dichas características se mantienen en la versión comercial. Desde la perspectiva de captura de requisitos usando técnicas para especificación de escenarios también existen trabajos relacionados. En [44] mediante un algoritmo se sintetizan diagramas de estados a partir de escenarios. Los escenarios son introducidos en forma incremental, comprobando su consistencia a través de animación de los diagramas de estados ya obtenidos. Un trabajo similar pero más orientado a la verificación del conjunto de escenarios se presenta en [90], donde además se introducen de restricciones de tiempo asociadas a las transiciones del diagrama de estados. Otras propuestas también orientadas a validación de requisitos usando escenarios son [61, 23]. En general en los trabajos antes indicados el interés se centra en el proceso de captura de requisitos mediante escenarios y la validación de los escenarios en sí mismos, es decir, la posterior elaboración y validación del modelo conceptual asociado quedan fuera de consideración. En los últimos años se ha registrado gran interés en torno a la validación de especificaciones formales mediante su animación [89]. Los trabajos más próximos al desarrollado en esta Tesis corresponden a propuestas para validación mediante animación en lenguajes formales cercanos en motivación a OASIS, por ejemplo los trabajos de animación en TROLL, en ALBERT y en TESORO. En lo que respecta a TROLL, en [33] se establecieron los conceptos y una arquitectura general para dar soporte de animación a una especificación en di11 http://www.aonix.com 2.3. TRABAJOS RELACIONADOS 21 cho lenguaje. Posteriormente, en [26] se bosqueja un ambiente para animación de especificaciones TROLL ligth (un dialecto de TROLL). En [36] se describe un prototipo muy preliminar de dicho ambiente, en el cual es posible explorar el estado de objetos, introducir ocurrencias de eventos y visualizar cambios de estado. Finalmente uno de los últimos trabajos de los que se tiene constancia es [28], en el cual no parece haber adelantos significativos respecto de las publicaciones anteriores. En cuanto a ALBERT, en [21] se presenta el diseño (en términos muy generales) de un ambiente para animación de especificaciones ALBERT. En [37] se propone comprobar escenarios respecto de la animación de una especificación ALBERT y se establece un proceso de validación basado en animación. En [38] se describe la funcionalidad y arquitectura para un módulo de animación de especificaciones ALBERT, además se presenta un prototipo muy rudimentario de una herramienta, donde la principal novedad respecto a trabajos anteriores en ALBERT es el manejo de varias sesiones de animación a la vez, posibilitando la validación cooperativa de escenarios. En [34] se describe un método que integra captura de requisitos basada en escenarios junto con validación mediante animación. Finalmente, en TESORO se han realizado algunos trabajos de prototipación pero orientados específicamente al estudio de protocolos de comunicación [13]. En resumen, en los enfoques cercanos a OASIS aunque existen precedentes en animación (automática en algunos casos), aún no existen resultados consolidados en lo que se refiere a herramientas disponibles, los entornos descritos son de carácter preliminar. Al contrastar los resultados presentados con las arquitecturas y funcionalidad preestablecidas en las publicaciones analizadas queda en evidencia que todavía hay mucho trabajo por realizar. Además, es importante destacar que en las publicaciones antes referenciadas no se proporcionan detalles del enfoque ni modelo de implementación utilizado, en este aspecto sólo se indica su existencia utilizando términos como TROLL-Kernel o ALBERT-Core. En el caso de OASIS se ha desarrollado una herramiena CASE (OOMETHOD CASE) basada en OO-METHOD. Sin embargo, tanto en OOMETHOD y como en el CASE asociado el esfuerzo se ha concentrado en la obtención automática del producto final (y en lenguaje imperativos). De esta forma, sólo es posible realizar validación exploratoria sobre el producto final. Por lo tanto, además del trabajo desarrollado en esta Tesis, no existen precedentes en lo que respecta a técnicas específicas para la validación de modelos conceptuales OASIS mediante animación automática. Con la realización de esta Tesis, en este aspecto OASIS queda en una situación favorable respecto de TROLL y ALBERT. 22 CAPÍTULO 2. ANTECEDENTES Capítulo 3 OASIS En este capítulo se presentan los conceptos básicos de OASIS, para mayores detalles tanto de aspectos teóricos o del lenguaje asociado consultar en [56]. El punto de partida para la realización de esta Tesis fue OASIS en su versión 2.2. Sin embargo, en el desarrollo de este trabajo surgieron propuestas de mejoras y extensiones que impulsaron en gran medida el establecimiento de la nueva versión OASIS 3.0. Estos aspectos, como aportes adicionales, serán tratados en mayor detalle en los siguientes capítulos donde se presentan: la incorporación de la perspectiva cliente, la interpretación homogénea de las especificaciones de procesos en el marco formal de la Lógica Dinámica utilizada y la interacción entre objetos. Una especificación OASIS es una presentación de una teoría en el sistema formal usado, expresada como un conjunto estructurado de definiciones de clase. Las clases pueden ser simples o complejas. Una clase compleja es aquella que en su definición utiliza la definición de otras clases (simples o complejas). Las clases complejas se definen utilizando operadores de clase. Estos son agregación y herencia. Una clase se compone de un nombre de clase, uno o más mecanismos de identificación para instancias de la clase (objetos) y un tipo o plantilla que comparten todas las instancias. La plantilla recoge las propiedades de estructura y de comportamiento compartidas por todos los objetos potenciales de la clase considerada. Para una clase simple todas las propiedades quedan establecidas en su plantilla. Para una clase compleja, además de las propiedades establecidas por su plantilla, existirán propiedades adicionales determinadas por las relaciones entre clases que la definen. 23 24 3.1. CAPÍTULO 3. OASIS Plantilla o tipo Definición 1 Plantilla o tipo. Una plantilla de clase está representada por una tupla hAtributos, Eventos, F órmulas, P rocesosi. Atributos es el alfabeto de atributos. ∀att ∈ Atributos, se tiene la función att : sort de nombrado → sort de evaluación Eventos es el alfabeto genérico de eventos. ∀e ∈ Eventos podemos obtener e= θe siendo θ una substitución básica de los posibles parámetros del evento. F órmulas es un conjunto de fórmulas en diversas lógicas según sea la sección del lenguaje donde se utilizan. P rocesos es el conjunto de especificaciones de proceso. Cada proceso se especificará usando un cálculo de procesos basado en un subconjunto del lenguaje propuesto en CCS [65]. Las especificaciones de proceso serán divididas en operaciones y protocolos. Definición 2 Servicio. Un servicio es un evento o una operación. En el primer caso se trata de un servicio atómico e instantáneo. Una operación es un servicio no atómico y que, en general, tiene duración. Definición 3 Acción. Una acción es una tupla hCliente,Servidor,Servicioi, que representa tanto la acción asociada a requerir el servicio en el objeto cliente como la acción asociada a proveer el servicio en el objeto servidor. El concepto de acción involucra tres elementos: un objeto cliente, uno o más (en caso de broadcast) objetos servidores y el servicio requerido desde el cliente al servidor (o servidores). En el objeto cliente ocurre la acción por solicitar el servicio al objeto servidor. Para la misma acción en el objeto cliente, en el objeto servidor ocurre la acción de proveer el servicio solicitado o la acción de rechazar dicha solicitud. Para cada clase, asumiremos la existencia implícita de un conjunto A de acciones obtenido a partir de los servicios que los objetos de la clase pueden requerir (cuando son clientes) o proveer (cuando son servidores). Al igual que para los eventos, ∀a ∈ Acciones podemos obtener a= θa siendo θ una substitución básica de los posibles cliente, servidor y servicio. 3.2. Ciclo de vida de un objeto Un objeto tiene dos aspectos: estructura (determinada por sus atributos) y comportamiento (aspecto asociado a las acciones que le acontecen). 3.2. CICLO DE VIDA DE UN OBJETO 25 Definición 4 Atributo. Un atributo es un par hnombre, sort de evaluacióni, siendo nombre el identificador del atributo y sort de evaluación el nombre del conjunto soporte (carrier) o valores que puede tomar dicho atributo. Definición 5 Atributo evaluado. Un atributo evaluado es un par hnombre, valori, siendo nombre el identificador usado para referirse al atributo y valor ∈ carrier(sort(nombre)). Si el valor de un atributo no cambia durante la vida del objeto diremos que el atributo es constante, en caso contrario el atributo es variable. Definición 6 Estado del objeto. Llamaremos estado del objeto al conjunto de sus atributos evaluados. Se expresa normalmente mediante Fbfs de una lógica de primer orden. Ejemplo 1 El estado de un objeto de la clase válvula podría ser: abierta=true y caudal=50. Ejemplo 2 El estado de un objeto de la clase coche podría ser: matricula= A-6065-CK, velocidad=80 y temperatura_del_motor=normal. El estado permite caracterizar a un objeto en un instante determinado. Sea Σ el conjunto de estados1 alcanzables por un objeto y σ ∈ Σ un estado en particular. El estado de un objeto cambia por la ocurrencia de acciones2 . Los cambios de estado son modelados por la siguiente relación: efecto : A → (Σ → Σ) Donde A es el conjunto de acciones instanciadas (a ∈ A) que le pueden acontecer al objeto y ef ecto es la función cambio de estado atómico que produce la ocurrencia de una acción. En un mismo instante de tiempo, a un objeto le puede acontecer más de una acción. Definición 7 Conjunto consistente de acciones. Un conjunto de acciones M ⊆ A es consistente si a partir de un estado σ dado, el estado σ0 alcanzado por la ocurrencia de todas las acciones en M es siempre el mismo, independiente del orden en el cual se ejecuten3 las acciones. P Los estados son fórmulas. El conjunto corresponde a estructuras de interpretación (mundos) de dichas fórmulas, aunque por sencillez hablaremos de estados. 2 Se considerará la frame assumption, es decir, supondremos que si no se especifica que la modificación del valor de un atributo se debe a la ocurrencia de una determinada acción, entonces dicho atributo no es modificado por dicha acción. 3 Se utilizará “ejecución de acción” como sinónimo de “ocurrencia de acción” para hacer más intuitiva la presentación. Sin embargo, desde el punto de vista declarativo y formal, “ocurrencia” es el término más adecuado. 1 26 CAPÍTULO 3. OASIS Definición 8 Paso. Llamaremos paso a un conjunto consistente de acciones que ocurren en un mismo instante de la vida del objeto. Sea µ = {a1 , ..., an } ⊆ A un paso. La relación de accesibilidad entre estados está determinada por µ, Rµ ⊆ Σ × Σ y se define como (siendo “◦” el símbolo de composición funcional) : def Rµ (σ) ≡ efecto(a1 )(σ) ◦ ... ◦ efecto(an )(σ) = σ0 De acuerdo con la definición de conjunto consistente, el orden en el cual se aplica la función efecto a las acciones no altera el estado siguiente alcanzado por el objeto. Definición 9 Vida o traza de un objeto. Llamaremos vida o traza de un objeto a un prefijo finito de pasos que le acontecen al objeto. De esta forma, la traza es una caracterización alternativa del estado del objeto en un instante determinado. A las vidas maximales las llamaremos ciclos de vida. En OASIS, el modelado del comportamiento puede realizarse desde dos perspectivas complementarias en cuanto a expresividad. En cada instante, para un objeto, las acciones permitidas y las acciones obligatorias pueden ser establecidas de la siguiente forma: Considerando el estado del objeto en dicho instante. Las precondiciones son fórmulas que permiten la ocurrencia de acciones sólo en ciertos estados del objeto. De forma análoga, los disparos son fórmulas que obligan la ocurrencia de acciones en determinados estados del objeto. Considerando las acciones ya acontecidas. Una especificación de proceso determina un patrón de comportamiento para el objeto desde el punto de vista de secuencias de pasos acontecidos, es decir, determina trazas posibles. En OASIS se utilizan dos tipos de especificaciones de proceso: protocols y operations. Un protocolo establece secuencias permitidas de acciones. Una operación establece secuencias obligatorias de acciones. 3.3. OASIS expresado en Lógica Dinámica OASIS está basado en una variante de la Lógica Dinámica [30] que incorpora obligaciones, prohibiciones y permisos. Siendo a ∈ A, en OASIS se utilizan los siguientes operadores: O(a) F (a) P (a) obligación de ocurrencia de a. prohibición de ocurrencia de a. permiso o habilitación de ocurrencia de a. 3.3. OASIS EXPRESADO EN LÓGICA DINÁMICA 27 La definición de dichos operadores en Lógica Dinámica es la siguiente [64]: F (a) ⇔ [a] false O(a) ⇔ [¬a] f alse P (a) ⇔ ¬F (a) “la ocurrencia de a está prohibida”. “la ocurrencia de a es obligatoria”. “a está permitida si y sólo si a no está prohibida”. Donde ¬a representa la no-ocurrencia de la acción a (es decir, que no ocurre nada o que ocurre otra acción distinta de a). En estas fórmulas, false es un átomo especial tal que no hay un estado que pueda hacerlo verdadero, es decir, cuando no existe una relación de alcanzabilidad definida4 . Esta situación podría representar un estado de violación del sistema. El significado intuitivo de éstas fórmulas es: una acción está prohibida si su ocurrencia conduce a un estado de violación. Una acción es obligatoria si su no-ocurrencia conduce a un estado de violación. La Lógica Dinámica es un formalismo natural para estudiar de forma simple y directa ciertas aserciones sobre programas. En Lógica Dinámica, la fórmula [a]φ se interpreta intuitivamente como “después de la ocurrencia de la acción a, φ debe satisfacerse”, siendo a una acción y φ una Fbf de la lógica de primer orden utilizada para caracterizar el estado. Siendo ψ y φ Fbfs de primer orden que caracterizan el estado del objeto inmediatamente antes (y después, respectivamente) de la ocurrencia de la acción a. Utilizaremos los siguientes tipos de fórmulas en Lógica Dinámica: ψ → [a]f alse ψ → [¬a]false ψ → [a]φ “la ocurrencia de a está prohibida en los estados que satisfacen ψ”. “la ocurrencia de a es obligatoria en los estados que satisfacen ψ”. “en los estados que satisfacen ψ, inmediatamente después de la ocurrencia de la acción a, φ debe satisfacerse”. Estas fórmulas constituyen un sublenguaje del lenguaje de Lógica Dinámica propuesto y formalizado en [97]. 4 En [64] Meyer utiliza la constante especial V (violation) en lugar de false para representar un mundo no válido o estado sub-ideal. Así, un objeto podría tener la posibilidad de transitar entre mundos no válidos hasta alcanzar un mundo válido. En nuestro caso la especificación OASIS establece sólo estados “ideales” con lo cual hemos preferido utilizar el átomo false para reflejar este hecho. 28 CAPÍTULO 3. OASIS MUNDOS ESTADOS PASOS inexistencia → w1 → w2 → ... → wi ... ... σ2 σi ... σ1 ... µ0 µi ... µ1 µ2 t0 t1 t2 ti → destrucción tdestroy Figura 3.1: Relación entre mundos, estados y pasos del objeto. 3.4. Semántica de OASIS La semántica de OASIS es dada en términos de una estructura de Kripke (W, τ , ρ). W es el conjunto de todos los mundos5 posibles que un objeto puede alcanzar. Sean F el conjunto de Fbf evaluadas sobre el estado (mundo asociado) en el cual se encuentra el objeto, A el conjunto de acciones de la signatura del objeto y 2A , el conjunto de instantáneas (pasos instanciados) posibles. Las funciones τ y ρ se definen como: τ : F → 2W ρ : 2A → (W → W ) La función τ asigna a una fórmula en Lógica de Predicados de Primer Orden el conjunto de mundos en los cuales se satisface. La función ρ asigna a cada paso una relación binaria entre mundos, la cual es la semántica declarativa del lenguaje. Siendo µ ∈ 2A y w, w0 ∈ W , el significado buscado es: (w, w0 ) ∈ ρ(µ) si y sólo si la ocurrencia de µ conduce al objeto desde el mundo w al mundo w0 . Definición 10 Transición válida. Cada par (w, w0 ) ∈ ρ(µ) se denomina transición válida. La relación entre estados, mundos, pasos y la vida del objeto se representa en la Figura 3.1. donde ti es el tiempo en el cual se produce el i-ésimo tick de reloj para el objeto. Se supone que µi ocurre en ti exactamente. Obviamente, se cumple que: |=wi σi , i = 1, ..., n. Así, la interpretación de las diferentes fórmulas en Lógica Dinámica, usadas en la plantilla de clase OASIS, es la siguiente: 1. Fórmulas del tipo ψ → [a]φ, en particular [a]φ, cuando ψ es true (cualquier estado del objeto) 5 De acuerdo con lo dicho, los estados son aserciones (fórmulas), los mundos son estructuras sobre las que dichas fórmulas son interpretadas. 3.5. CONCURRENCIA EN OASIS 29 Siendo w ∈ τ (ψ) el mundo actual, si a ocurre entonces el mundo alcanzado es w0 ∈ τ (φ) . Así, las evaluaciones establecen las propiedades que deben satisfacerse en el mundo alcanzado como efecto atómico de la ejecución de una acción. Dicho de otra forma: |=w ψ y |=w0 φ. 2. Fórmulas de prohibición ¬φ → [a]false Siendo w ∈ τ (φ) el mundo actual, si a ocurre, no existe por definición una transición válida. Es decir, una fórmula de prohibición impide que una acción ocurra estando el objeto en ciertos estados, aquellos donde |=w ¬φ. 3. Fórmulas de obligación φ → [¬a]false Siendo w ∈ τ (φ) el mundo actual, si la acción a no ocurre, no existe por definición un mundo válido alcanzable. Es decir, una obligación fuerza a que la acción a ocurra cada vez que el estado del objeto es tal que |=w φ. 3.5. Concurrencia en OASIS Como se estableció anteriormente, una especificación OASIS modela al sistema de información como una sociedad de objetos autónomos y concurrentes que se comunican entre sí a través de acciones. Así, de forma natural la concurrencia en una especificación OASIS está presente en las siguientes formas: Cada objeto tiene su propio hilo de ejecución. Un objeto puede necesitar cumplir más de una obligación (ocurrencia obligada de una acción) en el mismo instante. Sería una restricción bastante fuerte al modelado no permitir que en la especificación exista la posibilidad que se produzcan dos obligaciones en el mismo instante. Un objeto compuesto (por otros objetos) puede proveer o requerir más de un servicio a la vez. 3.6. Conclusiones del capítulo En este capítulo se han presentado las características esenciales de OASIS, incluyendo definiciones para los conceptos básicos y describiendo brevemente el marco formal utilizado. OASIS, tal como es presentado en [56] puede ser visto desde dos perspectivas: como la formalización de un conjunto de conceptos de 30 CAPÍTULO 3. OASIS modelado y como un lenguaje de especificación basado en dicha formalización. En este capítulo no se ha presentado OASIS como lenguaje sino sólo algunos de sus conceptos y su formalización. Por ejemplo, no se ha incluido el tratamiento de relaciones entre clases mediante especialización y agregación. Para más detalles consultar [56]. En los capítulos siguientes se incluyen algunos ejemplos utilizando la sintaxis de OASIS 3.0. Capítulo 4 Perspectiva cliente La perspectiva cliente de una objeto aparece como una capacidad expresiva adicional que permite representar el comportamiento activo del objeto (comportamiento del objeto como cliente) en términos homogéneos respecto del comportamiento pasivo (del objeto como servidor). Esto significa reconocer y tratar los servicios que un objeto requiere como acontecimientos relevantes en su vida, de la misma forma que lo son los servicios que el objeto provee. En OASIS 2.2 no se da esta capacidad expresiva. Para sistemas en los cuales no existen objetos activos o donde los únicos objetos activos son los usuarios de la aplicación esto no presenta mayores inconvenientes, pero obviamente en estas circunstancias quedan excluidos muchos otros sistemas. Desde el punto de vista de la animación, la incorporación de la perspectiva cliente se presentó como un problema a resolver. Para la animación de especificaciones OASIS se debía disponer de un modelo abstracto de ejecución que estableciera la semántica operacional del modelo. Durante el establecimiento de dicho modelo de ejecución se detectó que era imprescindible contar con la capacidad para expresar la perspectiva cliente en una especificación. Esta necesidad surgió cuando se intentaba dar una interpretación operacional para los disparos. Cuando la condición de un disparo se satisfacía en el estado actual del objeto, éste tenía la obligación de efectuar el disparo para alcanzar un estado siguiente válido (debía requerir un cierto servicio a otro objeto o a sí mismo). Inmediatamente surgía la necesidad de controlar la repetición del disparo, pues en cada estado alcanzado, si la condición de disparo aún se cumplía, el disparo continuaba siendo una obligación. OASIS debía proveer un mecanismo que permitiera controlar los disparos y de paso extender la expresividad del modelo en forma homogénea al resto de aspectos relacionados, es decir, otras fórmulas y especificaciones de proceso de la plantilla de clase. 31 32 CAPÍTULO 4. PERSPECTIVA CLIENTE 4.1. Repetición de disparos en OASIS 2.2 Analicemos la siguiente porción de una especificación OASIS 2.2 para la clase socio. class socio identification ... constant_attributes ... variable_attributes num_libros:nat; notificado:boolean; private_events alta_socio new; baja_socio destroy; notificar; shared_events prestar with libro; devolver with libro; valuations num_libros=N [prestar] num_libros=N+1; num_libros=N [devolver] num_libros=N-1; notificado=false [notificar] notificado=true; triggers self::notificar if num_libros=2 and notificado=false; ... El disparo del evento notificar hacia el mismo objeto corresponde a requerir dicho evento a sí mismo. El primer inconveniente que se presenta es distinguir entre el servicio requerido y el servicio provisto. En este caso, en el cual el cliente y el servidor son el mismo objeto, el servicio solicitado forma parte de la signatura del objeto, pero esto en general no sucede. Cuando se produce un disparo se establece una relación entre dos acciones: la que ocurre en el cliente por requerir y la que ocurre en el servidor por proveer o rechazar la solicitud de servicio. Es decir, en el ejemplo anterior una acción es requerir el evento notificar y otra es proveer el evento notificar. Así, la evaluación asociada a la ocurrencia del evento notificar se interpreta como una evaluación por proveer dicho evento, no por requerirlo. Además, nótese que el disparo, por la obligación que significa, se realizará en todos los estados que satisfagan la condición de disparo. Es decir, en estados sucesivos en los 4.1. REPETICIÓN DE DISPAROS EN OASIS 2.2 33 que la condición de disparo se siga satisfaciendo, el disparo continuará realizándose. Este comportamiento puede ser el deseado en algún caso particular pero en general se necesita un mecanismo que permita especificar con precisión cómo deben efectuarse los disparos. La solución dentro del contexto de OASIS es clara, debe poderse introducir una condición adicional dentro de la condición de disparo de manera que la realización del disparo pueda deshabilitarse. En el ejemplo planteado la condición que pretendía inhabilitar el disparo era “notificado=false”. A continuación veremos por qué el comportamiento deseado no se consigue. Para poder apreciar el problema primero se describirán brevemente algunos aspectos del modelo abstracto de ejecución para especificaciones OASIS, el cual se presenta en detalle en el capítulo 8. La vida del objeto se caracteriza por las acciones acontecidas en determinados instantes de tiempo y los correspondientes estados alcanzados. En cada instante ti el objeto tiene un buzón, un conjunto de servicios para proveer, el cual se denominará Mboxi . El estado del objeto permanece inalterado inmediatamente después de la ocurrencia de acciones en un instante y hasta el instante siguiente (inclusive), es decir, en un intervalo (t i - t i+1 ] el estado se mantiene constante pues no se procesan servicios. En el intervalo (t i - t i+1 ) el objeto está realizando actividad interna y sólo en t i+1 el estado alcanzado está disponible para procesar el siguiente buzón (Mboxi+1 ). Para representar gráficamente estas ideas se ha establecido una notación denominada Diagramas de Vida del Objeto. Un Diagrama de Vida del Objeto permite apreciar las acciones provistas y requeridas por un objeto y los cambios de estado alcanzados. La Figura 4.1 presenta un Diagrama de Vida del Objeto. En el capítulo 8 se muestra un ejemplo más completo respecto de la notación utilizada. De acuerdo a lo explicado antes, a continuación se proporciona una interpretación operacional para la especificación del ejemplo. Como se indicó antes, la evaluación asociada al evento notificar intenta deshabilitar la repetición del disparo, sin embargo, en el mejor de los casos, el disparo se efectuaría dos veces. Esto se ilustra en la Figura 4.1. Suponiendo que el objeto inicialmente tiene un estado representado por {<num_libros,0>,<notificado,false>} y que recibe dos solicitudes de servicio correspondientes a la ocurrencia del evento prestar. En el estado alcanzado en el instante t2 se satisface la condición de disparo. Por tratarse de una obligación, en ese mismo instante se requiere el servicio notificar representado con la flecha inferior. Debe insistirse en lo siguiente: requerir un servicio a sí mismo es sólo un caso particular, en general dicha solicitud puede ir dirigida a otro objeto. Además, el disparo debe hacerse efectivo en el instante en el cual el objeto alcanza el estado que valida la condición de disparo, no antes. Así, en el mejor de los casos, la solicitud de servicio hacia sí mismo será atendida en el instante inmediatamente siguiente a la realización del disparo, con lo cual en al menos dos estados consecutivos 34 CAPÍTULO 4. PERSPECTIVA CLIENTE se disparará el evento notificar (salvo que en t2 ocurra un evento devolver o un nuevo prestar, lo cual no es controlado por la especificación ni por la interpretación operacional asumida). prestar1 prestar2 t0 t1 Estado1 notificar1 t2 t3 Estado2 num_libros=1 notificado=false Estado3 num_libros=2 notificado=false Estado4 num_libros=2 notificado=false self::notificar1 num_libros=2 notificado=true self::notificar 2 Figura 4.1: Repetición de disparos La interpretación operacional que se ha propuesto está basada estrictamente en la semántica de la fórmula que establece la obligación asociada al disparo ( φ[¬e]false). En cada estado en el que se satisfaga la fórmula φ el evento e debe ocurrir en el cliente, independientemente de si el servicio es provisto o rechazado en el servidor, es decir, se trata de una comunicación asíncrona. 4.2. Incorporando la perspectiva cliente Según lo expuesto anteriormente, en OASIS 2.2 no existe una forma de controlar el disparo de eventos en la especificación. La incorporación de la perspectiva cliente resuelve este problema. Para una adecuada introducción de este aspecto en OASIS, se han tenido en cuenta las siguientes consideraciones: En un disparo si el servidor no es el mismo objeto, el servicio solicitado no está en la signatura del objeto cliente. Por el carácter asíncrono de los disparos es imprescindible hacer la distinción entre requerir el servicio (disparar en el cliente) y proveer el servicio (atender en el servidor). La expresividad adicional asociada a la perspectiva cliente es extensible a todas las fórmulas y especificaciones de proceso. 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE 35 Por otra parte, era importante mantener compatibilidad respecto de OASIS 2.2, de forma que la incorporación de la perspectiva cliente debía corresponder a una extensión de la expresividad original. Un enfoque descartado por su carácter revolucionario fue migrar hacia la línea de arquitecturas software o componentes . En el capítulo 6 se presenta una propuesta en este sentido. A continuación se introducen los elementos utilizados para modelar la perspectiva cliente en especificaciones OASIS. 4.2.1. Identificación de objetos Definición 11 Oid (object identifier). Cada objeto posee un oid. El oid establece la identidad del objeto y tiene las siguientes características: Constituye un identificador único y global para cada objeto dentro del sistema. Es determinado en el momento de la creación del objeto. Es independiente de la localización física del objeto, es decir, provee completa independencia de localización. Es independiente de las propiedades del objeto, lo cual implica independencia de valor y de estructura. No cambia durante toda la vida del objeto. Además, un oid no se reutiliza aunque el objeto deje de existir. No se tiene ningún control sobre los oids y su manipulación resulta transparente. Sin embargo, en el ámbito de la especificación y operación del sistema, es preciso contar con algún medio para hacer referencia a un objeto en particular. Definición 12 Mecanismo de identificación. Siendo Oids el conjunto de oids de objetos del sistema, C una clase y Oidsc el conjunto de oids de objetos de la clase C, entonces Oidsc ⊆ Oids. Además, siendo Att el conjunto de atributos de la clase C y Attcons ⊆ Att un conjunto de atributos constantes de la clase C, si {att1 , att2 , ..., attn } ⊆ Attcons y los sorts respectivos son s1 , s2 , ..., sn entonces puede existir un mecanismo de identificación, la función: id : s1 × s2 × ... × sn → Oidsc La función id establece una correspondencia entre una tupla de valores de atributos constantes y el oid de un objeto de la clase C, con oid ∈ Oidsc . La tupla representa el concepto de clave candidata. 36 CAPÍTULO 4. PERSPECTIVA CLIENTE Definición 13 Valor de un mecanismo de identificación. Siendo id un mecanismo de identificación, entonces llamamos valor de un mecanismo de identificación a id. Así, id = θ id y θ es una sustitución básica de los valores de atributos constantes que definen al mecanismo de identificación. Los mecanismos de identificación no son redundantes y permiten hacer referencia a objetos en el ámbito del problema, utilizando propiedades del objeto. Sin embargo, internamente la referencia e identificación del objeto son mediante su oid. Un objeto puede tener más de un mecanismo de identificación aunque cada vez que se hace referencia a un objeto se utiliza sólo uno de ellos. A partir de este punto se introducirán parcialmente aspectos de la sintaxis de OASIS para hacer más sencilla y precisa la exposición de los cambios introducidos. Sintaxis <def_identificador> ::= <id_identificador> ’:’ (<lista_id_atributo>) Cada atributo que define el mecanismo de identificación (en la lista <id_atributo>) es un atributo constante. Ejemplo 3 Una definición de tres mecanismos de identificación para los objetos de la clase despacho en un edificio. ocupante:(nombre); nro_ext_telefonica:(nro_ext_telefonica); ubicacion:(edificio, planta, puerta); Cuando un mecanismo de identificación se define a base de sólo un atributo, puede usarse para denotarlo el mismo nombre del atributo. 4.2.2. Referencias a cliente y servidor La necesidad de hacer referencia a otros objetos (de la clase que se está especificando o de otra clase) está estrechamente ligada a la interacción entre objetos. Este apartado se centra en mostrar cómo hacer referencia a objetos en la especificación de una clase, sean clientes o servidores de las acciones que acontecen. 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE 37 Sintaxis <ref_objeto> <identificación> ::= ::= | | | <valor_atributo> ::= self <clase> [<identificación>] ’(everyone)’ ’(someone)’ ’(’<id_identificador>’,’ ’[’<lista_valor_atributo>’]’ ’)’ <expresión> | ’_’ Observaciones Cuando se desea hacer referencia al mismo objeto que se está especificando se utilizará la palabra reservada self. Para hacer referencia a cada uno de los objetos de la clase se utiliza (everyone). Si se quiere referenciar a un objeto de una clase (sin especificar uno en concreto) se utiliza (someone). Para referirse a un conjunto de objetos que coinciden en alguno de los valores de la lista de valores de atributo se indicará el mecanismo de identificación y la lista de valores de atributos llevará los valores que deben coincidir en las posiciones adecuadas. Se utiliza ’_’ para señalar que se admite cualquier valor. Si todas las posiciones tienen un ’_’ el efecto es el mismo que usar (everyone). Ejemplo 4 El objeto de la clase despacho cuyo ocupante es Juan Pérez. despacho(ocupante,[‘‘Juan Perez’’]) Ejemplo 5 El objeto de la clase despacho cuyo número de extensión telefónica es 3571. despacho(nro_ext_telefonica,[3571]) Ejemplo 6 El objeto de la clase despacho ubicado en el edificio EUI, tercera planta y puerta A3. despacho(ubicacion,[‘‘EUI’’,3,‘‘A3’’]) Ejemplo 7 Un objeto cualquiera de la clase despacho. despacho(someone) 38 CAPÍTULO 4. PERSPECTIVA CLIENTE Ejemplo 8 Cada uno de los objetos de la clase despacho. despacho(everyone) Ejemplo 9 Los objetos de la clase despacho ubicados en el edificio de la EUI. despacho(ubicacion,[‘‘EUI’’,_,_]) 4.2.3. Acciones El concepto de acción incluye tres elementos: referencia del cliente, referencia del servidor y descripción del servicio. Así, una acción está definida por la tupla hCliente, Servidor, Servicioi. El cliente requiere un servicio a un servidor que ofrece dicho servicio. El servicio puede ser un evento o una operación (concepto que se presenta en el siguiente capítulo) . Las referencias del cliente y del servidor se definen según lo explicado en el apartado anterior. El servicio es un término instanciado mediante una sustitución de valores adecuados en sus parámetros. Ejemplo 10 Una acción cuyo cliente es un objeto de la clase usuario y cuyo servidor es un objeto de la clase cuenta, siendo depósito(15000) el servicio requerido. <usuario(nombre,[‘‘Juan Perez’’]), cuenta(numero,[100]),deposito(15000)> Ejemplo 11 Una acción cuyo cliente y servidor es el mismo objeto, donde pagar_comisión es el servicio requerido. <self,self,pagar_comision> Ejemplo 12 Una acción cuyo cliente es un objeto de la clase administrador y cuyo servidor son todos los objetos de la clase artículo, siendo aumentar_precio(5) el servicio requerido. <administrador(nombre,[‘‘Maria’’]), articulo(everyone),aumentar_precio(5)> Ejemplo 13 Una acción cuyo cliente es un objeto de la clase goloso y cuyo servidor es un objeto de la clase máquina (máquina de chocolatinas), siendo cancelar el servicio solicitado. <goloso(nombre,[‘‘Juan Perez’’]), 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE Servicios provistos Objeto 39 Servicios requeridos acción Objeto A Objeto B Figura 4.2: Perspectivas cliente y servidor de un objeto. maquina(numero,[10]),cancelar> Ejemplo 14 Una acción cuyo cliente es un objeto cualquiera de la clase goloso y cuyo servidor es un objeto de la clase máquina (máquina de chocolatinas), siendo introducir_moneda el servicio solicitado. <goloso(someone),maquina(numero,[10]),introducir_moneda> Nótese que al establecer el servicio de una acción no se hace distinción entre requerir un evento o requerir una operación. Esto constituye una ventaja puesto que el cliente no tiene por qué saber detalles de implementación del servicio que requiere. La Figura 4.2 muestra cómo un objeto tiene una perspectiva cliente y una perspectiva servidor según esté requiriendo u ofreciendo servicios, respectivamente. Modelar la perspectiva cliente significa tener la posibilidad de reflejar en la especificación de la clase cliente el hecho de que “todo servicio requerido también es un evento para el objeto cliente”. Ambas perspectivas son tratadas uniformemente bajo la noción de acción antes descrita. En la especificación de una clase, las acciones asociadas a servicios provistos o requeridos se incluyen en la definición de fórmulas (precondiciones, evaluaciones y disparos) y de especificaciones de procesos. Las acciones en su formato completo (hCliente, Servidor, Servicioi) pueden dificultar la lectura y edición de la especificación. Para evitar este inconveniente se pueden utilizar las siguientes simplificaciones: a) Cuando se trata de un servicio provisto por el objeto (el propio objeto es el servidor) la acción se escribirá como Cliente:Servicio. Si el cliente no es relevante se escribirá sólo Servicio. 40 CAPÍTULO 4. PERSPECTIVA CLIENTE b) Cuando se trata de un servicio requerido por el objeto (el propio objeto es el cliente) la acción se escribirá como Servidor::Servicio. c) En el caso particular en el cual el cliente y el servidor son el mismo objeto se debe diferenciar entre la acción de requerir el servicio y la acción de proveerlo. En este caso se escribirá ::Servicio para representar la acción por requerir y self :Servicio para representar la acción por proveer. Sintaxis <acción> <cliente> <servidor> ::= ::= ::= [ <cliente> ] [ <servidor> ] <servicio> <ref_objeto> ’:’ <ref_objeto> ’::’ | ’::’ Ejemplo 15 En la clase cuenta, una evaluación asociada a la acción cuyo cliente es un objeto cualquiera y cuyo servidor es el propio objeto de la clase cuenta, siendo el servicio depósito(Cantidad:int). saldo=S [deposito(Cantidad)] saldo=S+Cantidad; “Cuando saldo=S y ocurre la acción cuyo evento es deposito(Cantidad), inmediatamente después se cumple que saldo=S+Cantidad” Ejemplo 16 En la clase cuenta, una parte de una expresión de proceso (supondremos que se trata de una operación) en la cual el cliente y servidor de una acción corresponden al objeto de la clase cuenta (la clase que se está especificando), siendo el servicio pagar_comisión. ... AJUSTAR4= ::pagar_comision.AJUSTAR5; ... “Cuando el estado del proceso es AJUSTAR4, debe ocurrir la acción cuyo cliente y servidor es el objeto de la clase especificada (cuenta). El evento de la acción es pagar_comisión. Después de ocurrida la acción el estado del proceso es AJUSTAR5”. Ejemplo 17 En la clase administrador, una obligación de ejecutar la acción cuyo cliente es un objeto de la clase administrador y cuyo servidor son todos los objetos de la clase artículo, siendo el servicio aumentar_precio(Porcentaje:int). ventas > 1000000 [¬articulo(everyone)::aumentar_precio(5)] false “Al satisfacerse ventas > 1000000 debe ocurrir una acción cuyo cliente es el objeto de la clase especificada (administrador), el servidor es cada objeto de la clase artículo y el servicio es aumentar_precio(5)”. 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE 41 Ejemplo 18 En la clase máquina, una precondición para una acción cuyo cliente es el objeto de la clase goloso “Juan Pérez” y cuyo servidor es el mismo objeto (máquina de chocolatinas), siendo chocolatina el servicio solicitado. ¬(numero_chocs>10) [goloso(nombre,[‘‘Juan Perez’’]):chocolatina] false “Se prohibe que cuando el número de chocolatinas (numero_chocs) es menor que 10 acontezca el servicio chocolatina requerido por el objeto de la clase goloso cuyo nombre es Juan Pérez”. En la especificación de una clase, el servicio de una acción es siempre un servicio de la clase servidora. Es decir, a menos que la clase servidora sea self, dicho servicio no está en la signatura de la clase cliente. Sin embargo, en el ámbito de una acción vista como una tupla hCliente, Servidor, Servicioi, tanto las acciones recibidas como las acciones enviadas pertenecen a la signatura de la clase especificada. 4.2.4. Control de disparos En este apartado se muestra un ejemplo que ilustra cómo mediante la incorporación de la perspectiva cliente es posible controlar la repetición de los disparos, situación que motivó dicha incorporación. Ejemplo 19 Las instancias de la clase Y tienen declarado un disparo hacia la instancia de la clase Z identificada por “z1”. La condición de disparo es “att1=2 and att2=false”. La especificación resumida de las clases Y y Z es la siguiente : class Y identification by_att0 (att0 ); constant_attributes att0 :nat; variable_attributes att1 : nat ; att2 : boolean(false); private_events ... e1 ; valuations att1 =N [e1 ] att1 =N+1 and att2 =false; [Z(by_code,[(code,’’z1 ’’)])::e2 ] att1 =0 and att2 =true; 42 CAPÍTULO 4. PERSPECTIVA CLIENTE triggers Z(by_code,[(code,’’z1 ’’)])::e2 if att1 =2 and att2 =false; ... class Z identification by_code(code); constant_attributes code: string; ... events e2 ; ... Z(by_code,[(code,’’z1 ’’)]) es el término servidor para representar al objeto de la clase Z usando el mecanismo de identificación by_code compuesto por el atributo constante code, el cual debe tener el valor “z1 ”. Para facilitar la lectura del ejemplo, se hará referencia a Z(by_code,[(code,’’z1 ’’)]) usando sólo Z(’’z1 ’’). Si en el instante ti se alcanza el estado Statei en el cual debe ocurrir el disparo Z(’’z1 ’’)::e2 , entonces en Mboxi estará la acción Z(’’z1 ’’)::e2 , indicando la obligación del disparo. En este caso, aunque e2 no está en la signatura del cliente podremos utilizar esta acción para reflejar el evento “disparar e2 ”. Posteriormente, en la evaluación “att2 =false [Z(’’z1 ’’)::e2 ] att1 =0 and att2 =true” se consigue controlar la repetición del disparo. Como se observa en la especificación de Y, el evento e1 volverá a habilitar la condición de disparo. Suponiendo una ejecución para una instancia de la clase Y en la cual las acciones llegan de acuerdo a la siguiente tabla : Intervalo (ti - ti+1] (.. - t1] (t1 - t2] (t2 - t3] (t3 - t4] (t4 - t5] (t5 - t6] (t6 - .. Acciones Recibidas e1 e1 Z(“z1”)::e2 e1 e1 Z(“z1”)::e2 ... El Diagrama de Vida del Objeto de la Figura 4.3 describe parte del ciclo de vida de una instancia de la clase Y. Se ha considerado como estado inicial {<att1 ,0>,<att2 ,false>}. 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE e1 e1 43 e1 e1 Mbox1 Mbox2 Mbox3 Mbox4 Mbox5 Mbox6 e1 e1 Z(“z 1”)::e 2 e1 e1 Z(“z 1”)::e 2 t1 att =1 t2 att1=0 1 att2=false att2=false t3 att1=2 att2=false att1=0 att2=true t4 att1=1 att2=false t5 att1=2 t6 att1=0 att2=false Z(“z 1”):e 2 att2=true Z(“z 1”):e 2 Figura 4.3: Parte del ciclo de vida de un objeto de la clase Y. La siguiente tabla resume el comportamiento del objeto mostrado en la Figura 4.3. i Intervalo (ti - ti+1] (.. (t1 (t2 (t3 (t4 (t5 (t6 - t1] t2] t3] t4] t5] t6] .. State att1=0, att1=1, att1=2, att1=0, att1=1, att1=2, att1=0, att2=false att2=false att2=false att2=true att2=false att2=false att2=true Acciones Acciones Ejecutadas en Disparadas en ti+1 ti+1 e1 e1 Z(“z1”)::e2 Z(“z1”):e2 e1 e1 Z(“z1”)::e2 Z(“z1”):e2 ... ... Acciones Recibidas e1 e1 Z(“z1”)::e2 e1 e1 Z(“z1”)::e2 ... Existe un caso particular en el cual el servidor de un disparo es el mismo objeto que requiere el servicio. Analicemos el siguiente caso: las instancias de la clase X tienen declarado un disparo a self cada vez que se satisface la fórmula “att1 =2 and att2 =false”. La especificación resumida de la clase X es la siguiente: class X identification by_att0 (att0 ); constant_attributes att0 : nat; variable_attributes 44 CAPÍTULO 4. PERSPECTIVA CLIENTE att1 : nat(0); att2 : boolean(false); private_events ... e1 ; e2 ; valuation att1 =N [e1 ] att1 =N+1; [self:e2 ] att1 =0 and att2 =false; [::e2 ] att2 =true; triggers ::e2 if att1 =2 and att2 =false; ... Cada vez que un objeto de la clase X alcance un nuevo estado, tendrá en su Mboxi las acciones correspondientes a los disparos que en ese estado satisfacen su condición. Por lo tanto, en el instante ti donde se alcanza el estado Statei , en el cual deba lanzarse el disparo self::e2 , en Mboxi estará la acción self::e2. Nótese que en la especificación existe una evaluación asociada a la ocurrencia del disparo (::e2) y otra asociada a proveer el servicio requerido en el disparo (self:e2). La acción de disparo ::e2 representa la obligación para el objeto. La acción de servicio self:e2 representa la solicitud de un servicio cuyo cliente es el mismo objeto. Suponiendo una ejecución para una instancia de la clase X en la cual las acciones llegan de acuerdo a la siguiente tabla: Intervalo (ti - ti+1] (.. - t1] (t1 - t2] (t2 - t3] (t3 - t4] (t4 - t5] (t5 - t6] (t6 - .. Acciones Recibidas e1 e1 ::e2 self:e2 e1 ... En t3 la condición de disparo de la acción ::e2 se satisface, por lo tanto en Mbox3 se introduce la obligación ::e2, la cual al ser ejecutada provocará que efectivamente se requiera la acción self:e2, la cual se ha supuesto que es recibida en el intervalo (t3 -t4 ]. El Diagrama de Vida del Objeto de la Figura 4.4 describe la situación planteada. Se ha considerado el estado inicial {<att1 ,0>,<att2 ,false>}. 4.2. INCORPORANDO LA PERSPECTIVA CLIENTE e1 e1 45 e1 Mbox1 Mbox2 Mbox3 Mbox4 e1 e1 ::e2 self:e 2 t1 att =1 t2 att1=0 1 att2=false att2=false t3 att1=2 att2=false att1=2 att2=true Mbox5 Mbox6 e1 t4 att1=0 att2=false t5 t6 att1=0 att2=false att1=1 att2=false self:e 2 Figura 4.4: Parte del ciclo de vida de un objeto de la clase X. La siguiente tabla resume el comportamiento del objeto mostrado en la Figura 4.4. i Intervalo (ti - ti+1] (.. - t1] (t1 - t2] (t2 - t3] (t3 - t4] (t4 - t5] (t5 - t6] (t6 - .. State att1=0, att1=1, att1=2, att1=2, att1=0, att1=0, att1=1, att2=false att2=false att2=false att2=true att2=false att2=false att2=false Acciones Ejecutadas en ti+1 e1 e1 ::e2 self:e2 e1 ... Acciones Disparadas en ti+1 self:e2 ... Acciones Recibidas e1 e1 ::e2 self:e2 e1 ... El cambio de estado es instantáneo pero cada estado se mantiene al menos hasta que se vuelvan a servir las acciones del buzón del siguiente instante. El objeto automáticamente introduce en su buzón una acción asociada a requerir un servicio cuando en el siguiente instante la condición de disparo se satisface, tal como se ha representado en el intervalo (t2 - t3 ]. Dicha acción provoca que el objeto efectivamente requiera al servidor el servicio involucrado en el instante en el cual la condición de disparo se satisface. Independientemente y en un instante posterior, el servicio requerido es provisto o rechazado por el objeto servidor. 46 4.3. CAPÍTULO 4. PERSPECTIVA CLIENTE Conclusiones del capítulo En este capítulo se ha establecido una extensión a OASIS 2.2 que permite un tratamiento homogéneo de la perspectiva cliente y servidor de un objeto. La propuesta presentada aumenta la capacidad expresiva de OASIS y soluciona el problema de OASIS 2.2 para el control de los disparos. Para cada clase, se asume la existencia implícita de un conjunto A de acciones obtenido a partir de los servicios que los objetos de la clase pueden requerir (cuando son clientes) o proveer (cuando son servidores). Es decir, aunque en general el servicio no pertenece a la signatura de servicios del objeto cliente, la acción por requerir cualquier servicio sí pertenece a su signatura. El tratamiento de los disparos es sólo un aspecto del tratamiento de obligaciones. En el capítulo 8 se presenta el modelo abstracto de ejecución para especificaciones OASIS que abarca obligaciones en el sentido más amplio. La perspectiva cliente puede expresarse no sólo en disparos y evaluaciones. De acuerdo a lo establecido anteriormente, podrían declararse clientes y servidores cada vez que se especifique un servicio tanto en fórmulas como en especificaciones de proceso. Sin embargo, a continuación se mencionan ciertas consideraciones al respecto: Las acciones que representan el requerir un servicio no deberían tener precondiciones ni especificaciones de proceso que pudiesen impedir su ejecución. Esto se debe a que dichas acciones son una obligación. Esto estaría en conflicto con la prohibición que establezca una precondición o especificación de proceso. Esta situación se resuelve con el siguiente enfoque de modelado: las prohibiciones que se quieran establecer para una obligación pueden ser especificadas como parte de la condición de disparo o de la especificación de proceso correspondiente. Declarar clientes y servidores asociados a los servicios crea dependencia de la clase especificada respecto al contexto en el cual se especifica (el esquema conceptual). Esto tiene incidencia negativa en la reutilización de la clase, lo cual sugiere reducir al mínimo las especificaciones de clientes y servidores. En el caso de los servicios requeridos, con el enfoque propuesto siempre debe indicarse el objeto servidor, a menos que se trate del mismo objeto. Respecto de los clientes, estos siempre podrían evitarse, aún a coste de introducir nuevos servicios cuando se necesite diferenciar el mismo servicio para distintos clientes (por ejemplo porque tienen distintas evaluaciones). De esta forma, desde el punto de vista de una clase, el cliente de un servicio es quien tenga acceso a dicho servicio. Esta relación de acceso puede definirse en OASIS mediante interfaces. Capítulo 5 Especificaciones de proceso En este capítulo se presenta una nueva propuesta para la especificación de procesos en OASIS, en la cual la expresividad ofrecida es trasladable directamente a la variante de Lógica Dinámica utilizada en las otras secciones de la plantilla de clase. Es decir, la formalización de las especificaciones de proceso puede ser establecida dentro de un marco formal homogéneo para toda la plantilla de clase. Una herramienta para el modelado conceptual debe combinar precisión y expresividad. La expresividad no sólo involucra tener la posibilidad de definir todos los aspectos de funcionalidad del sistema, sino que a la vez que éstos puedan ser definidos de forma natural tanto para el analista como para el usuario. En la práctica el mejor resultado se obtiene combinando diversas técnicas de especificación. Sin embargo, esto dificulta la integración y formalización de la especificación. Tradicionalmente en métodos orientados a objeto suele utilizarse tres vistas del sistema: modelo de objetos, modelo dinámico y modelo funcional [81]. En OASIS 2.2 el modelo dinámico incluye dos formas complementarias de especificación de eventos permitidos y obligados en la vida de un objeto: a partir del estado (mediante disparos y precondiciones) y en base a secuencias de eventos acontecidos (transacciones y procesos). En el primer caso se trata de fórmulas en una variante de lógica dinámica y en el otro se utiliza un álgebra de procesos. En la construcción automática de prototipos para especificaciones OASIS el disponer como entrada de una representación uniforme es muy importante para facilitar el proceso de traducción y para garantizar la fidelidad respecto de la especificación. Esto motivó la búsqueda de un formalismo homogéneo para el modelo dinámico de OASIS. La idea era mantener la expresividad, es decir, posibilitar la especificación a partir del estado y en base a secuencias de eventos, pero proporcionando una interpretación equivalente que integre ambas perspectivas en un formalismo común. Se ha distinguido entre procesos 47 48 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO que establecen obligaciones (operations) y procesos que establecen permisos (protocols) proporcionando una semántica precisa en cada caso. Además, una serie de inconvenientes presentes en OASIS 2.2 han sido solventados. 5.1. Procesos en OASIS 2.2 En OASIS 2.2 cada clase tiene una especificación de proceso, construida utilizando un Álgebra de Procesos para Objetos (APO) la cual es una extensión conservativa del Álgebra Básica de Procesos propuesta en [96]. Se han detectado los siguientes inconvenientes en el enfoque utilizado en OASIS 2.2 para la especificación de procesos: La formalización ofrecida no es uniforme respecto a la usada para el resto de la plantilla de clase. En las secciones de evaluaciones, precondiciones y disparos se utiliza una variante de Lógica Dinámica. En procesos se utiliza la APO mencionada antes. Los procesos de OASIS 2.2 determinan permisos para eventos e incluyen sólo la perspectiva servidor del objeto. En el caso de transacciones, se especifica explícitamente el agente de cada evento involucrado en la transacción o se asume que es uno de los agentes del primer evento de la transacción. En general, es difícil establecer una especificación de proceso para una clase, a menos que sea muy simple, esto sucede, por ejemplo, si el objeto se crea y después puede proveer cualquier servicio hasta que es finalmente destruido. Más difícil aún es establecer sólo una especificación de proceso para la clase si se incluye la perspectiva cliente, pues entre las secuencias permitidas deberían incluirse los disparos, los cuales se rigen por el estado del objeto y no por secuencia de eventos. Además, en la práctica cuando se trata de establecer secuencias permitidas de eventos, éstas no tienen por qué involucrar a todos los eventos del objeto. Una especificación de proceso no asociada a una clase en particular se modela como transacción global. En estos casos, una solución más natural en el marco de OASIS es la definición de una clase agregada a la medida de las necesidades de visibilidad que requiera el proceso. Así, sólo en el caso extremo en que todas las clases del esquema estén involucradas la definición del proceso se haría en la clase agregada que representa al esquema conceptual. 5.2. PROCESOS EN OASIS 3.0 5.2. 49 Procesos en OASIS 3.0 Las ideas presentadas a continuación se han materializado en la versión 3.0 de OASIS. En este apartado se presenta un procedimiento automatizable para interpretar las especificaciones de proceso como fórmulas en la variante de Lógica Dinámica utilizada. Así, desde una perspectiva global, una especificación de clase OASIS puede ser vista como un conjunto de fórmulas en dicha Lógica Dinámica. Estas fórmulas determinan permisos, obligaciones y cambios de estado para los objetos de la clase. Además, la nueva propuesta incorpora la perspectiva cliente y permite definir sólo las especificaciones de proceso necesarias, cada una incluyendo sólo las acciones que le son relevantes. En OASIS 3.0, el modelado del comportamiento puede realizarse desde dos perspectivas complementarias en cuanto a expresividad. En cada instante, para un objeto, las acciones permitidas y las acciones obligatorias pueden ser establecidas de la siguiente forma: Considerando el estado del objeto en dicho instante. Las precondiciones son fórmulas que permiten la ocurrencia de acciones sólo en ciertos estados del objeto. De forma análoga, los disparos son fórmulas que obligan la ocurrencia de acciones en determinados estados del objeto. El formalismo utilizado en este caso es una variante de Lógica Dinámica que incluye los operadores deónticos de permiso, prohibición y obligación. Considerando las acciones ya acontecidas. Una especificación de proceso determina un patrón de comportamiento para el objeto, desde el punto de vista de secuencias de pasos acontecidos, es decir, determina trazas posibles. Para OASIS 3.0 se estableció la utilización de dos tipos de especificaciones de proceso: protocolos y operaciones. Un protocolo establece secuencias permitidas de acciones. Una operación establece secuencias obligatorias de acciones. Las especificaciones de proceso se expresan usando álgebra de procesos. Las propuestas más populares para la especificación de secuencias de acciones están basadas en los statecharts [31] o alguna de sus derivaciones, tal como los objectcharts [11]. En comparación a los objectcharts, la expresividad lograda por las especificaciones de procesos en OASIS es similar. Existen tres semánticas posibles que pueden ser asociadas a una especificación de proceso en OASIS 3.0: (a) La semántica del lenguaje utilizado para su especificación. En OASIS, el lenguaje utilizado para especificar procesos es un subconjunto de CCS [65], compartiendo así una semántica basada en la noción de sistema de transición etiquetado y todas las propiedades formales establecidas en CCS. 50 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO (b) La semántica de permisos, es decir, una especificación de proceso establece secuencias de acciones que pueden ocurrir. (c) La semántica de obligaciones, es decir, una especificación de proceso establece secuencias de acciones que deben ocurrir. Dichas secuencias de acciones vienen dadas por la relación de alcanzabilidad entre mundos en el modelo de Kripke asociado. Un proceso en OASIS 3.0 tendrá siempre la semántica (a). Adicionalmente, se asocia la semántica (b) ó (c) a un proceso, esto se declara de forma explícita. Así, la sección operations se utiliza para especificar secuencias obligatorias de acciones y la sección protocols para especificar secuencias permitidas de acciones. Un caso particular de proceso de obligación es el que actúa como una transacción, es decir, con la política del “todo o nada”. En este caso se añade el calificativo de transaction para el proceso. Se asume por defecto que el proceso no actúa como transacción. Siguiendo el planteamiento y notación propuestos en CCS, la especificación de un proceso R puede ser vista como un sistema de transiciones etiquetado a representado por (κR , AR , {→: a ∈ AR }), donde: κR es el conjunto de constantes agente1 utilizados para definir el proceso R. AR es el conjunto de acciones usadas en la especificación del proceso R, AR ⊆ A, siendo A el conjunto de acciones2 en la signatura de la clase. a →⊆ κR × κR es la relación de transición. Para cada constante agente E ∈ κR se tiene una ecuación de definición def E ≡ Q, siendo Q una expresión construida usando los siguientes operadores (siendo S ∈ κR y a, a1 y a2 acciones pertenecientes al conjunto AR ): 1. a.S, se denomina prefijo. 2. if C then a.S, se denomina condicional, siendo C una expresión boolean. P P 0 0 3. i∈I Qi , donde Qi puede ser un prefijo o un condicional y i∈I es la 0 suma de los Qi , con I como conjunto de indexación. 1 Un proceso de OASIS en CCS corresponde al concepto de agente. Un agente está representado por una constante agente (su nombre). En la definición de una constante agente se pueden utilizar otras constantes agente, es decir, otros agentes. 2 Incluye tanto las acciones generadas desde otros objetos (o el mismo objeto) como las acciones generadas por el propio objeto. Es decir, el objeto visto como cliente y servidor. 5.2. PROCESOS EN OASIS 3.0 51 Existe P una constante adicional e implícita denotada por 0 y definida como 0 = i∈I ai .Si , con I = ∅. Por lo tanto, desde 0 no existen transiciones posibles. Extensiones del tipo if C then a1 .S1 else a2 .S2 pueden ser definidas escribiéndolas como (if C then a1 .S1 ) + (if ¬C then a2 .S2 ). Ejemplo 20 A continuación se especifica un proceso P y se detalla el sistema de transiciones asociado. P P1 def ≡ def ≡ def a.P1 b.P2 + e.P3 ≡ c.P2 + b.P2 + d.P1 ≡ 0 κP AP a → = = = b = = {P, P1 , P2 , P3 } {a, b, c, d, e} {(P, P1 )} d = = P2 P3 → c → → e → def {(P1 , P2 ), (P2 , P2 )} {(P2 , P2 )} {(P2 , P1 )} {(P1 , P3 )} Definición 14 Estado del proceso. Llamaremos estado del proceso a la constante agente que en un determinado instante representa al proceso. Un proceso puede ser representado por un grafo de transiciones. La Figura 5.1 muestra el grafo de transiciones para el proceso P del ejemplo. De acuerdo con el lenguaje que se ha definido para especificar procesos, un estado de proceso coincide con una constante agente del proceso, y a su vez, se corresponde con un nodo del grafo de transiciones del proceso. Esto es relevante para establecer una formalización directa y sencilla para las especificaciones de proceso. Las especificaciones de proceso utilizadas corresponden a una representación que se ha denominado “representación canónica” respecto de otras en las cuales se deja mayor libertad para la construcción de expresiones agente, las cuales tienen su equivalente en la representación canónica. Ejemplo 21 Una especificación de proceso para un cajero automático. Primero se muestra una versión no canónica de la representación del proceso y a continuación la correspondiente especificación canónica tal como se entiende en este trabajo. 52 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO P a P3 e P1 b d P2 c b Figura 5.1: Grafo de transiciones del proceso P. ATM1 = new_ATM.ATM2; ATM2 = destroy_ATM.ATM5 + read_card.(cancel + ::check_card_w_bank(n,p).ATM3).::eject.::ready.ATM2; ATM3 = bad_PIN_msg + card_accepted.(cancel + issue_transaction(n,m).ATM4); ATM4 = dispense_cash(m) + TA_failed_msg; ATM5 = 0; 5.2. PROCESOS EN OASIS 3.0 53 ATM5 ATM1 new_ATM destroy_ATM ATM2 ::ready read_card ::eject cancel dispense_cash(m) ::check card w bank(n,p) bad_PIN_msg TA_failed_msg ATM4 ATM3 cancel card_accepted issue_transaction(n,m) Figura 5.2: Representación del proceso en su forma no canónica. El grafo de transiciones asociados se muestra en la Figura 5.2. Como se puede observar, existen nodos del grafo que no coinciden con constantes agentes que definen el proceso. A continuación se presenta la misma especificación de proceso en su forma canónica. ATM1 ATM2 ATM3 ATM4 ATM5 ATM6 ATM7 ATM8 ATM9 = = = = = = = = = new_ATM. ATM2; destroy_ATM.ATM9 + read_card. ATM3; cancel.ATM7 + ::check_card_w_bank(n,p).ATM4; bad_PIN_msg.ATM7 + card_accepted.ATM5; cancel.ATM7 + issue_transaction(n,m).ATM6; dispense_cash(m).ATM7 + TA_failed_msg.ATM7; ::eject.ATM8; ::ready.ATM2; 0; El grafo de transiciones para esta nueva representación del proceso se muestra en la Figura 5.3. En este caso cada nodo del grafo coincide con una con- 54 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO stante agente de la definición del proceso. ATM9 ATM1 new_ATM destroy_ATM ATM2 ::ready ATM8 read_card ::eject ATM3 cancel ATM7 dispense_cash(m) ::check_card_w_bank(n,p) bad_PIN_msg TA_failed_msg ATM6 ATM4 cancel card_accepted ATM5 issue_transaction(n,m) Figura 5.3: Representación del proceso en su forma canónica. En la plantilla de clase OASIS 3.0, para cada proceso R existe implícitamente un atributo variable de sort κR con el mismo nombre del proceso. Dicho atributo representa el estado del proceso (la constante agente o nodo del grafo de transiciones asociado) en el cual se encuentra el proceso. Como veremos, cuando el objeto está en el estado 0 en un determinado proceso, el comportamiento del objeto no está siendo afectado por el proceso (el proceso no determina ni permisos ni obligaciones para el objeto). Nótese que un mismo estado del proceso puede estar asociado a más de un estado del objeto (un σ distinto). 5.2.1. Procesos como fórmulas en Lógica Dinámica Como se ha expuesto, los operadores de la Lógica Deóntica que expresan obligaciones, prohibiciones y permisos pueden ser vistos como una variante de 5.2. PROCESOS EN OASIS 3.0 55 Lógica Dinámica. Esto sugiere que los procesos de obligación y prohibición se corresponden del mismo modo con fórmulas en Lógica Dinámica. Una especificación de proceso determina una conducta particular del objeto. Diremos que un proceso afecta a un objeto si el objeto debe comportarse según la conducta establecida por dicho proceso. Comúnmente, el objeto seguirá la conducta del proceso en partes de su vida. Un caso particular es un proceso que afecta al objeto durante toda su existencia. Un proceso que establece permisos se puede expresar como un conjunto de fórmulas en Lógica Dinámica de la forma ¬φ → [a]f alse, del mismo modo que se indicó para las fórmulas de precondiciones. De forma análoga, un proceso que establece obligaciones se puede expresar como un conjunto de fórmulas en Lógica Dinámica de la forma ψ → [¬a]f alse, como se hace para las fórmulas de disparos. Como veremos, en ambos casos se obtendrán adicionalmente fórmulas por transición de estado del proceso. Estas fórmulas son del mismo tipo usado para evaluaciones, es decir, ψ → [a]φ0 . a Sea R un proceso definido por el sistema de transiciones (κR , AR , {→: a ∈ a a AR }), E,E 0 ∈ κR . Si (E, E 0 ) ∈→, esto suele escribirse como E → E 0 y se dice que a es una acción desde E. Ejemplo 22 Utilizando el proceso P presentado en el ejemplo 20. De acuerdo con el sistema de transiciones de P , se tiene que: a es una acción desde P , b es una acción desde P1 y desde P2 , c es una acción desde P2 , d es una acción desde P2 y e es una acción desde P1 . Definición 15 Predicado de ocurrencia de una acción en un estado del proceso. Sea r el atributo variable asociado al estado del proceso R. Si a es una acción desde un estado E del proceso, llamaremos predicado de ocurrencia de a en E al predicado ((r = E) ∧ C) y lo denotaremos por ΩEa . Siendo C la expresión boolean cuando la transición (E, E 0 ) tiene definida una condición C. Si la transición no tiene condición el predicado de ocurrencia de a en E es (r = E). Además, por defecto, si a no es una acción desde E, entonces ΩEa ≡ false. Ejemplo 23 Los predicados de ocurrencia de cada acción en cada estado del proceso P son: 56 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO ΩP a ΩP1 b ΩP2 b ΩP2 c ΩP2 d ΩP1 e ≡ ≡ ≡ ≡ ≡ ≡ (p = P ) (p = P1 ) (p = P2 ) (p = P2 ) (p = P2 ) (p = P1 ) Para el resto de combinaciones entre estado del proceso y acciones, el predicado de ocurrencia es f alse. Definición 16 Predicado de ocurrencia de una acción en un proceso. Ampliando el concepto anterior al proceso como un todo, llamaremos predicado de ocurrencia de a en R, denotado por ΩR∗ a , a la disyunción de predicados de ocurrencia de a desde E, para cada constante agente E que define al proceso R. Ejemplo 24 Los predicados de ocurrencia en P para cada una de sus acciones, son: ΩP ∗ a ΩP ∗ b ΩP ∗ c ΩP ∗ d ΩP ∗ e ≡ ≡ ≡ ≡ ≡ (p = P ) ((p = P1 ) ∨ (p = P2 )) (p = P2 ) (p = P2 ) (p = P1 ) El significado de ΩR∗ a es el siguiente: “ΩR∗ a se satisface si y sólo si el proceso R está en algún estado de proceso E y algún ΩEa se satisface, es decir, a es una acción desde E y además se cumple la condición C asociada (si ésta existe)”. a Así, un proceso R, definido por el sistema de transiciones (κR , AR , {→: a ∈ AR }), se corresponde con las fórmulas en Lógica Dinámica presentadas a continuación. Fórmulas por transiciones. Efectúan la evolución del proceso de acuerdo a las transiciones definidas a y a la ocurrencia de acciones. Para cada a ∈ AR , y para cada (E, E 0 ) ∈→ se 0 obtiene la siguiente fórmula: ΩEa → [a](r = E ). Ejemplo 25 Las fórmulas por transiciones para el proceso P son: 5.2. PROCESOS EN OASIS 3.0 (p = P ) (p = P1 ) (p = P2 ) (p = P2 ) (p = P2 ) (p = P1 ) → → → → → → 57 [a](p = P1 ) [b](p = P2 ) [b](p = P2 ) [c](p = P2 ) [d](p = P1 ) [e](p = P3 ) Además, siendo anew la acción de creación para instancias de la clase, entonces: a) Si R es un proceso que establece obligaciones entonces, además, existirá la fórmula: [anew ](r = 0) Es decir, asumimos que un proceso de obligación no afecta al objeto desde el comienzo de su existencia. b) Si R es un proceso que establece permisos, la fórmula adicional es: [anew ](r = E1 ) E1 ∈ κR es la constante agente de inicio del proceso. Es decir, asumimos que un proceso de permiso afecta al objeto desde el comienzo de su existencia. Fórmulas por Permisos (sólo si R es un proceso que establece permisos). De acuerdo con el estado del proceso, una fórmula de permiso establece la situación en la cual la ocurrencia de una acción se permite. Para cada a ∈ AR se obtiene la siguiente fórmula: ¬ΩR∗ a → [a]f alse. Ejemplo 26 Si en el ejemplo tratado, el proceso P fuera un proceso que establece secuencias de acciones permitidas, las fórmulas de permiso asociadas serían: ¬(p = P ) ¬((p = P1 ) ∨ (p = P2 )) ¬(p = P2 ) ¬(p = P2 ) ¬(p = P1 ) → → → → → [a]false [b]false [c]f alse [d]false [e]false 58 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO Fórmulas por Obligaciones (sólo si R es un proceso que establece obligaciones). De acuerdo al estado del proceso, una fórmula de obligación establece la situación en la cual la ocurrencia de una acción es obligatoria. Para cada a ∈ AR se obtiene la siguiente fórmula: ΩR∗ a → [¬a]false. Ejemplo 27 Si en el ejemplo tratado, el proceso P fuera un proceso que establece secuencias de acciones obligatorias, las fórmulas de obligación asociadas serían: (p = P ) ((p = P1 ) ∨ (p = P2 )) (p = P2 ) (p = P2 ) (p = P1 ) 5.3. → → → → → [¬a]false [¬b]false [¬c]f alse [¬d]false [¬e]false Un ejemplo más extenso Considerar la siguiente especificación OASIS 3.0 para una clase “Máquina de venta de chocolatinas”. Se tiene la operación CANCEL que devuelve al usuario las monedas introducidas. Además, el protocolo GETCHOC determina que sólo se aceptan hasta tres monedas, pudiendo obtener hasta tres chocolatinas en una compra. 5.3. UN EJEMPLO MÁS EXTENSO 59 class vm identification number: (number); constant attributes number: nat. variable attributes num_chocs: nat; credit: nat(0); switch_on: bool(false); events set new; coin_in; coin_out; choc; light_empty; operations CANCEL: CANCEL1= {credit>1}::coin_out.CANCEL1 + {credit<=1}::coin_out; triggers ::light_empty when {nchocs=0 and switch_on=false}; valuations [coin_in] credit=credit+1; [::coin_out] credit=credit-1; [choc] nchocs=nchocs-1, credit=credit-1; [::light_empty] switch_on=true; preconditions choc if {credit>0 and nchocs>0}; CANCEL if {credit>0}; protocols GETCHOC: GETCHOC1= coin_in.GETCHOC2; GETCHOC2= choc.GETCHOC1 + coin_in.GETCHOC3 + ::coin_out.GETCHOC1; GETCHOC3= choc.GETCHOC2 + coin_in.GETCHOC4 + ::coin_out.GETCHOC2; GETCHOC4= choc.GETCHOC3 + ::coin_out.GETCHOC3; end class El sistema de transición de estados para la operación CANCEL es el siguiente: κCANCEL = {CANCEL1, 0} ACANCEL = {::coin_out} coin_out → = {(CANCEL1,CANCEL1), (CANCEL1,0)} 60 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO CANCEL 1 ::coin_out 0 ::coin_out Figura 5.4: Grafo de transiciones para la operación CANCEL La figura 5.4 muestra el grafo de transiciones para la operación CANCEL. El sistema de transición de estados para el protocolo GETCHOC es el siguiente: κGETCHOC = {GETCHOC1, GETCHOC2, GETCHOC3, GETCHOC4} A GETCHOC = {coin_in, choc, ::coin_out} coin_in → = {(GETCHOC1,GETCHOC2), (GETCHOC2,GETCHOC3), (GETCHOC3,GETCHOC4)} choc → = {(GETCHOC2,GETCHOC1), (GETCHOC3,GETCHOC2), (GETCHOC2,GETCHOC3)} coin_out → = {(GETCHOC2,GETCHOC1), (GETCHOC3,GETCHOC2), (GETCHOC2,GETCHOC3)} La figura 5.4 muestra el grafo de transiciones para el protocolo GETCHOC. choc GETCHOC1 coin_in ::coin_out choc choc coin_in GETCHOC2 GETCHOC3 ::coin_out coin_in GETCHOC4 ::coin_out Figura 5.5: Grafo de transiciones para el protocolo GETCHOC A continuación se presentan las fórmulas en Lógica Dinámica asociadas a la clase vm Fórmulas de cambio de estado Evaluaciones explícitamente definidas 5.3. UN EJEMPLO MÁS EXTENSO 61 credit=N −→ [coin_in] credit=N+1 credit=N −→ [::coin_out] credit=N-1 nchocs=N ∧ credit=M −→ [choc] nchocs=N-1 ∧ credit=M-1 [::light_empty] switch_on=true Evaluaciones por las transiciones del proceso GETCHOC [set] getchoc=GETCHOC1 getchoc=GETCHOC1 −→ [coin_in] getchoc=GETCHOC2 getchoc=GETCHOC2 −→ [coin_in] getchoc=GETCHOC3 getchoc=GETCHOC3 −→ [coin_in] getchoc=GETCHOC4 getchoc=GETCHOC2 −→ [choc] getchoc=GETCHOC1 getchoc=GETCHOC3 −→ [choc] getchoc=GETCHOC2 getchoc=GETCHOC4 −→ [choc] getchoc=GETCHOC3 getchoc=GETCHOC2 −→ [::coin_out] getchoc=GETCHOC1 getchoc=GETCHOC3 −→ [::coin_out] getchoc=GETCHOC2 getchoc=GETCHOC4 −→ [::coin_out] getchoc=GETCHOC3 Evaluaciones por transiciones del proceso CANCEL [set] cancel=0 [CANCEL] cancel=CANCEL1 cancel=CANCEL1 ∧ credit>1−→ [::coin_out] cancel=CANCEL1 cancel=CANCEL1 ∧ credit=1−→ [::coin_out] cancel=0 Fórmulas de prohibición Fórmulas explícitamente definidas q(nchocs>0 ∧ credit>0) −→ [choc] false q(credit>0) −→ [CANCEL] false Fórmulas por prohibiciones desde el proceso GETCHOC q((getchoc=GETCHOC1) ∨ (getchoc=GETCHOC2) ∨ (getchoc=GETCHOC3)) −→ [coin_in] false q((getchoc=GETCHOC2) ∨ (getchoc=GETCHOC3) ∨ (getchoc=GETCHOC4)) −→ [choc] false q((getchoc=GETCHOC2) ∨ (getchoc=GETCHOC3) ∨ (getchoc=GETCHOC4)) −→ [::coin_out] false 62 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO Fórmulas de obligación Fórmula explícitamente definida nchocs=0 ∧ switch_on=false −→ [q::light_empty] false Fórmula por la obligación desde el proceso CANCEL (cancel=CANCEL1 ∧ credit>1) ∨ (cancel=CANCEL1 ∧ credit<=1) −→ [q::coin_out] false A continuación se presenta una especificación equivalente para la “Máquina de venta de chocolatinas”, en la cual según la formalización presentada, las especificaciones de proceso han sido interpretadas como fórmulas en la misma variante de lógica dinámica utilizada para el resto de la plantilla. class vm identification number: (number); constant attributes number: nat; variable attributes num_chocs: nat; credit: nat; # atributos variables usados para cambios en procesos # cancel:nat; getchoc:nat; events set new; coin_in; coin_out; choc; light_empty; # el evento de inicio de la operacion CANCEL # CANCEL; triggers ::light_empty when {nchocs=0 and switch_on=false}; # disparo correspondientes a la operación CANCEL # ::coin_out when {(credit>1 and cancel=1) or (credit<=1 and cancel=1)}; valuations [coin_in] credit=credit+1; [::coin_out] credit=credit-1; [choc] nchocs=nchocs-1, credit=credit-1; [::light_empty] switch_on=true; # evaluaciones correspondientes a la operación CANCEL # 5.4. ASPECTOS ADICIONALES 63 [set] cancel=0; [CANCEL] cancel=1; {credit>1 and cancel=1} [::coin_out] cancel=1; {credit<=1 and cancel=1} [::coin_out] cancel=0; # evaluaciones correspondientes al protocolo GETCHOC # [set] getchoc=1; getchoc=1 [coin_in] getchoc=2; getchoc=2 [coin_in] getchos=3; getchoc=3 [coin_in] getchoc=4; getchoc=2 [choc] getchoc=1; getchoc=3 [choc] getchoc=2; getchoc=4 [choc] getchoc=3; getchoc=2 [::coin_out] getchoc=1; getchoc=3 [::coin_out] getchoc=2; getchoc=4 [::coin_out] getchoc=3; preconditions choc if {credit>0 and nchocs>0}; CANCEL if {credit>0}; # precondiciones correspondientes al protocolo GETCHOC # coin_in if {getchoc=1 or getchoc=2 or getchoc=3}; choc if {getchoc=2 or getchoc=3 or getchoc=4}; coin_out if {getchoc=2 or getchoc=3 or getchoc=4}; end class 5.4. Aspectos adicionales Manteniendo el marco formal establecido, en este apartado se presentan aspectos adicionales que extienden la capacidad expresiva que puede ser usada en especificaciones de proceso. Tratamiento de pasos y operaciones Un paso es un conjunto consistente de acciones que acontecen en un instante dado en la vida de un objeto. Una acción está asociada a un servicio. El servicio puede ser un evento o una operación. El evento no tiene duración, es instantáneo. En cambio, una operación establece una secuencia obligatoria de acciones y, en general, tiene una duración. El cliente no tiene porqué conocer si un servicio corresponde a un evento o una operación en el servidor. Por esto, en la acción acontecida en el cliente, y que refleja la solicitud del servicio, no se hace referencia alguna que distinga entre solicitar un evento o solicitar una operación. En el servidor, el tratamiento para servir una operación es distinto al dado cuando el servicio es un evento. Al proveer operaciones consideraremos lo siguiente: 64 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO Se asume que las precondiciones o evaluaciones (si existen) asociadas a una operación son precondiciones o evaluaciones para el evento de inicio de la operación. Para asegurar la correcta realización de una operación, mientras una operación esté en ejecución, no deben servirse otros eventos ni operaciones que hagan incompatible el concepto de paso (conjunto consistente de acciones) con la obligatoriedad de ejecución de las acciones de la operación3 . Una operación puede ser vista como una secuencia de acciones (las que determina su especificación) más dos acciones implícitas: la acción de inicio de la operación y la acción de término de la operación. La acción de inicio tiene siempre un evento requerido por un determinado cliente (quien solicita la operación). La acción de término tiene siempre un evento requerido a sí mismo, obligado e inmediatamente posterior a la ejecución de la última acción ejecutada por la operación. El mantener implícito las acciones de inicio y término de operación simplifica la especificación. Al mismo tiempo, apoya la idea de que tanto eventos como operaciones sean tratados en la especificación bajo un concepto más amplio; el concepto de servicio. A continuación, se abordará el tratamiento de operaciones, sólo para mostrar la correspondencia con la formalización de procesos ya realizada (en la que no se discutió el tratamiento de operaciones). Sea op una operación definida para el objeto. Denotaremos por op• a la acción de inicio de la operación y por op¯ a la acción de término de la operación. Si existiera una precondición como: ¬φ → [op]f alse, se interpretaría implícitamente como una precondición para la acción de inicio de la operación, es decir, ¬φ → [op• ]f alse. Del mismo modo, una evaluación del tipo ψ → [op]φ se interpreta como una evaluación asociada a la acción de inicio de la operación, es decir, ψ → [op• ]φ. Según lo anterior, el tratamiento de operaciones se reduce a la ejecución de las acciones de la operación más las dos acciones implícitas de inicio y fin de la operación. Queda por asegurar que al permitirse concurrencia intra-objeto (de eventos y operaciones), las acciones de un paso sean siempre consistentes y a la vez se cumpla la obligatoriedad de las acciones de una operación en ejecución. 3 El problema es análogo al de control de concurrencia de transacciones, ampliamente tratado en bases de datos relacionales. Nótese que la definición previa de paso era aplicable sólo para acciones ejecutadas en un mismo instante. Este concepto debe ser extendido para considerar cierta duración asociada a la ejecución de una operación. 5.4. ASPECTOS ADICIONALES 65 La no-consistencia entre acciones es difícil de establecer. Sin embargo, la consistencia se cumple siempre si las acciones no están en conflicto4 . El conjunto de atributos sobre el cual puede tener efecto una operación está determinado por la unión de los conjuntos de atributos sobre los cuales tienen efecto las acciones incluidas en la operación. Asociado a cada operación, existe un atributo implícito del objeto que determina en qué estado de la operación se encuentra el objeto. Si la operación no está en ejecución entonces dicho atributo toma el valor 0. Siendo op el atributo que registra el estado del proceso op, entonces existe una evaluación implícita del tipo [op¯ ](op = 0). Esta evaluación hace que inmediatamente después de ejecutarse la acción op¯ (acción de término del proceso), el proceso op se encuentre en su estado de proceso 0, es decir, el proceso vuelve a una situación de inactividad. Por lo tanto, para asegurar que los eventos y operaciones (tratadas como acciones) de un paso no estén en conflicto, además de verificar que no estén en conflicto entre ellas, debe verificarse que no estén en conflicto con ninguna operación en ejecución (cuyo valor de atributo asociado es diferente a 0). Capacidad para especificar procesos anidados Cuando las especificaciones de procesos son extensas (muchos estados de proceso) es conveniente disponer de algún mecanismo de descomposición. Así, un proceso puede ser descompuesto en subprocesos anidados5 especificados separadamente. Esto a su vez promueve la reutilización de especificaciones de subprocesos desde distintos procesos definidos en la plantilla de una clase. Ejemplo 28 Consideremos la especificación de un proceso L. Por simplicidad, supondremos que las acciones a1 y a2 son acciones cuyo servicio es un evento. L L1 L2 L3 def ≡ def a1 .L1 ≡ a2 .L1 + Q• .Q ≡ a1 .L3 def def ≡ 0 4 Dos acciones no están en conflicto si tienen efecto sobre conjuntos disjuntos de atributos. Este criterio es bastante restringido respecto de la concurrencia intra-objeto. Sin embargo, es fácil de determinar: basta con inspeccionar las evaluaciones asociadas a las acciones y posibles derivaciones de atributos. 5 Por anidamiento entendemos la capacidad expresiva que permite que un proceso en su definición haga referencia a otro proceso como una forma de transición compleja, definida por otro proceso. 66 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO Q Q1 Q2 def ≡ a2 .Q1 + a1 .Q2 def Q¯ .L2 def ≡ ≡ a1 .Q + a2 .Q2 Q• y Q¯ son dos acciones. Dichas acciones pueden verse como las acciones de inicio y de término para un cierto proceso (Q), respectivamente. Esto sugiere escribir L como: def L L1 L2 L3 ≡ a1 .L1 ≡ a2 .L1 + q.L2 def def ≡ def ≡ a1 .L3 0 Donde q es una acción que incluye al servicio no atómico Q. Así, el proceso L es definido utilizando la especificación del proceso Q, reescrito como: Q Q1 Q2 def ≡ def a2 .Q1 + a1 .Q2 ≡ a1 .Q + a2 .Q2 ≡ 0 def El proceso Q podría entonces ser utilizado en otras definiciones de proceso. A su vez, el proceso Q también podría utilizar otras definiciones de proceso. Así, la justificación de este anidamiento de especificaciones de proceso se obtiene estableciendo la correspondencia de la especificación anidada con una equivalente sin anidamiento. 5.5. Conclusiones del capítulo Se ha presentado una nueva propuesta para la especificación de procesos en OASIS. Para la especificación de un proceso se utiliza un subconjunto de CCS, asociándose una semántica adicional de obligación o permiso (prohibición) según se trate de una operación o un protocolo, respectivamente. De esta forma, las especificaciones de proceso pueden ser directamente interpretadas como un conjunto de fórmulas en la variante de Lógica Dinámica utilizada en el resto de la plantilla de clase. Así, se dispone una representación homogénea para representar el comportamiento de los objetos de una clase. Esto facilita la animación de especificaciones OASIS puesto que el proceso de traducción automática sólo debe tratar con una expresividad (la determinada 5.5. CONCLUSIONES DEL CAPÍTULO 67 por la variante de Lógica Dinámica usada), aunque en la especificación OASIS la especificación del comportamiento se pueda hacer tanto desde el punto de vista del estado del objeto como de las acciones acontecidas. 68 CAPÍTULO 5. ESPECIFICACIONES DE PROCESO Capítulo 6 Interacción entre objetos En este capítulo se introduce la noción de interacción entre objetos. En OASIS, un sistema de información es una sociedad de objetos autónomos, concurrentes y que interactúan entre sí. La interacción entre objetos está basada en comunicación. Para animar una especificación OASIS era necesario contar con una interpretación operacional de la comunicación entre objetos determinada por una especificación. Además, la introducción de la perspectiva cliente motivo un replanteamiento de los aspectos de comunicación en OASIS 2.2. El capítulo está estructurado de la siguiente forma: Se presentan los mecanismos de comunicación disponibles en OASIS 2.2, realizando comparaciones con el modelo usado por TROLL. Posteriormente se introduce un nuevo esquema de comunicación para OASIS, que extiende al usado por la versión 2.2 y que ha sido incorporado en OASIS 3.0. Finalmente se presenta un enfoque alternativo más cercano a la filosofía de TROLL e inspirado en arquitecturas software. 6.1. Comunicación entre objetos en OASIS 2.2 En OASIS 2.2 para establecer comunicación entre objetos se dispone de dos mecanismos de comunicación: disparos y eventos compartidos. En OASIS 2.2 al especificar la clase servidora es posible etiquetar los eventos con los agentes que pueden requerir dichos eventos, usando la notación a:e, donde a determina el objeto agente y e el evento solicitado. 6.1.1. Disparos En la Figura 6.1 se representa el mecanismo de disparos según el cual un objeto de la clase C puede actuar como cliente requiriendo el servicio e a un objeto de la clase S. Un caso particular de disparo es aquel en el cual en la 69 70 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS especificación de la clase del cliente no se declara el disparo, sin embargo, en una fórmula o especificación de proceso de la clase del objeto servidor junto al servicio provisto aparece una referencia de agente. En este caso se trata de una relación cliente-servidor en la cual el cliente puede solicitar el servicio de forma espontánea. c e class C ... triggers S(s)::e if ... ... e s class S ... ... c:e ... ... Figura 6.1: Disparos en OASIS 2.2 La fórmula en lógica dinámica que rige los disparos en OASIS 2.2 es: φ[¬e]f alse, que establece que cuando se satisface φ debe ocurrir e. El primer inconveniente que aparece es que la fórmula de disparo forma parte de la especificación del cliente, por lo que e en general es un evento que no está en la signatura del cliente sino en la del servidor. La incorporación de la perspectiva cliente resuelve este problema. Además, la fórmula de disparo determina una obligación sólo en el cliente, no en el servidor. Así, un disparo debería representar una comunicación asimétrica. Es decir, en un disparo la ocurrencia del evento en el cliente debe ser una obligación, no así en el servidor, donde el evento podría ser rechazado, por ejemplo por no satisfacerse una precondición. La Figura 6.2 muestra como un disparo puede ser interpretado como el paso de un mensaje un objeto cliente hacia un objeto servidor. 6.1.2. Eventos compartidos Un evento compartido es una comunicación simétrica y síncrona, todos los objetos que comparten el evento juegan un papel de servidor. La ejecución del evento compartido en cualquiera de los objetos que comparten dicho evento sólo es posible si el evento ocurre en todos los participantes. El mecanismo de comunicación por eventos compartidos corresponde a la abstracción de un conjunto de comunicaciones. La aplicación principal de este mecanismo se centra en la sincronización entre las vidas de objetos agregados y las vidas de sus componentes para todos aquellos eventos que sean relevantes. El disponer de esta abstracción facilita la especificación de dicha sincronización permitiendo abstraerse de detalles de implementación del protocolo de comunicación aso- 6.1. COMUNICACIÓN ENTRE OBJETOS EN OASIS 2.2 71 Cliente Statei-1 ti ti+1 Statei Statei+1 e e Servidor Statej-1 tj Statej tj+1 Statej+1 Figura 6.2: Interpretación de un disparo como el paso de un mensaje. ciado. La Figura 6.3 muestra dos situaciones de compartición de eventos, a la izquierda se trata de dos objetos pertenecientes a clases entre las cuales no existe una relación estructural, en la parte derecha el objeto x es un agregado cuyo componente es el objeto y. La ocurrencia del evento e debe ocurrir en ambos objetos servidores o en ninguno de ellos. e c x e e c e x e e y y Figura 6.3: Eventos compartidos en OASIS 2.2 En un nivel de implementación al establecer este mecanismo de comunicación para un entorno en el cual los objetos son autónomos y concurrentes es necesario utilizar un protocolo de confirmación de dos fases. Así, un proceso actuará como coordinador y se encargará de concertar a los participantes y verificar si todos pueden proveer el servicio. Se realizaron varios experimentos para la implantación de este tipo de comunicación usando Programación Lógica Concurrente (ver [46]). A continuación se muestra un protocolo para este tipo de comunicación y en el cual uno de los propios objetos servidores desempeña las tareas de coordinación. El protocolo se muestra en la Figura 72 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS 6.4 y consta de los siguientes pasos: 1. El cliente requiere el evento compartido de uno de los servidores que comparten dicho evento. Esta comunicación en el cliente corresponde directamente a un disparo desde el cliente o puede tratarse de un evento activo (requerido por el cliente sin que explícitamente se incluyan en la especificación la causa de su ocurrencia). 2. El servidor que recibe la solicitud de servicio actúa de coordinador y dispara el evento compartido al resto de servidores que comparten el evento. Al mismo tiempo el servidor-coordinador verifica la admisibilidad del evento según su estado. El servidor-coordinador queda a la espera de la confirmación desde los otros objetos servidores. 3. Cada servidor (excepto el coordinador) verifica la admisibilidad del evento y dispara un evento hacia el coordinador, indicando si el evento sería admitido o no. Si dicho servidor no admitiera el evento queda liberado en cuanto a sincronización, sin embargo, si admitiera el evento, deberá esperar a la confirmación desde el servidor-coordinador. 4. Con todas las confirmaciones recibidas (incluyendo la suya), el servidorcoordinador verifica si son todas positivas o existe alguna negativa. Si todos admitieran el evento, el servidor-coordinador dispara al resto de servidores la confirmación positiva. Si algún servidor no admitiera el evento, para cada servidor que respondió afirmativamente (y que está en espera) se dispara una confirmación negativa. Además, el servidorcoordinador dispara al cliente un evento que indica el éxito o fracaso de su solicitud. La Figura 6.4 ilustra el protocolo en el caso de respuestas afirmativas en todos los objetos servidores involucrados. 5. Si el evento es admitido por todos los objetos que lo comparten, en cada servidor, incluyendo al coordinador, ocurre (se ejecuta) el evento. En OASIS existen eventos compartidos implícitos producto de la necesaria coordinación entre las vidas de un objeto agregado respecto de sus componentes, por ejemplo: crear (o destruir) un objeto agregado, destruir un objeto componente, insertar un objeto componente, remover un objeto componente, cualquier evento que modifique un atributo en el componente y que a su vez dicho atributo esté siendo utilizado (mediante visibilidad) por el objeto agregado. 6.1.3. Comparación entre OASIS 2.2 y TROLL TROLL es quizás el lenguaje de especificación más cercano a OASIS. Resulta interesante analizar el enfoque seguido en TROLL para modelar interacción 6.1. COMUNICACIÓN ENTRE OBJETOS EN OASIS 2.2 73 client server 1 verify(event) no_error answer_ok conf_ok client event server k verify(event) server i answer_ok server 1 server k conf_ok server i verify(event) verify(event) answer_ok server n conf_ok server n Figura 6.4: Un protocolo para implementar eventos compartidos. entre objetos antes de proponer un nuevo esquema de comunicación entre objetos para OASIS. A continuación se presentan comparaciones entre OASIS 2.2 y TROLL respecto de cómo se realiza la interacción entre objetos. En OASIS 2.2 los disparos son un mecanismo de comunicación asíncrono y los eventos compartidos representan comunicación síncrona pero sólo entre objetos servidores. En TROLL el event calling, el único mecanismo de comunicación ofrecido es siempre síncrono, la relación calling e1 >> e2 entre los eventos e1 y e2 establece que cada vez que ocurre e1 , e2 también debe ocurrir (aunque e2 puede ocurrir sin que ocurra e1 ). En TROLL la ocurrencia de e1 en general no es una obligación, pues está supeditada a la ocurrencia de e2 . En TROLL todos los eventos son locales al objeto y se declaran explícitamente, es decir, están en su signatura. Por lo tanto, la perspectiva cliente está ya incorporada. Las relaciones cliente-servidor en OASIS se establecen mediante disparos declarados explícitamente en la clase cliente y/o mediante especificación de agentes en la clase servidora. En TROLL, cuando se desea establecer una comunicación cliente-servidor y los objetos involucrados tienen una 74 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS relación de agregado-componente existen dos situaciones: si se quiere establecer una relación de causalidad desde el agregado hacia el componente se utiliza el apartado calling en la sección events tal como se ilustra en la parte izquierda de la Figura 6.5, en cambio si el sentido de la causalidad es desde el componente hacia el agregado se utiliza la sección interactions tal como se muestra en la parte derecha de la Figura 6.5. Cuando los objetos no están relacionados estructuralmente es necesario utilizar un constructor adicional llamado relationships. En una relationship se establecen relaciones de event calling que sincronizan ejecuciones de eventos en un cliente con ejecuciones de eventos en un servidor, esto se ilustra en la Figura 6.6. e’ X e Y class X components Comp:Y ... events e’ calling Comp(y).e ... e’ X e Y class X components Comp:Y ... events e’ interaction Comp(y).e >> e’ ... Figura 6.5: Caso de objetos relacionados estructuralmente. e’ A object class A ... events e’ ... e B object class B ... events e ... relationship AB between A Client, B Server interaction Client.e’ >> Server.e ... Figura 6.6: Caso de objetos no relacionados estructuralmente. Los eventos compartidos de OASIS 2.2 equivalen en TROLL a una especificación de event calling en los dos sentidos, es decir, e1 >> e2 y e2 >> e1 . El event calling de TROLL establece directamente la causalidad entre eventos. Esto ocasiona inconvenientes difíciles de solucionar al establecer una interpretación operacional para la comunicación, que sea consistente respecto de la semántica de la especificación. Una propuesta de 6.2. UN NUEVO ESQUEMA DE COMUNICACIÓN 75 interacción entre objetos para TROLL [32] muestra las dificultades para conseguir asegurar la terminación y no postergación indefinida al usar event calling. En OASIS no existe causalidad directa entre eventos. Sin embargo, un evento puede provocar indirectamente un disparo si su ocurrencia hace que se satisfaga una condición de disparo en el estado alcanzado. Con esto se consigue en forma indirecta el efecto de causalidad entre eventos. Sin embargo, el enfoque de OASIS no presenta los inconvenientes de TROLL al momento de establecer una interpretación operacional para la comunicación entre objetos. 6.2. Un nuevo esquema de comunicación En esta sección se presenta un nuevo enfoque para la interacción entre objetos. Basado en lo expuesto anteriormente se mejora el esquema para comunicación entre objetos provisto por OASIS 2.2. En esta sección cuando no se haga una referencia explícita de la versión de OASIS, se debe entender que se trata de OASIS 3.0, aunque en los ejemplos se ha preferido utilizar una sintaxis más cercana al formalismo del modelo en lugar de la sintaxis concreta de OASIS 3.0. La incorporación de la perspectiva cliente y el concepto de operación llevan de forma natural hacia la noción de acción, en la cual se utiliza el término servicio para referirse en forma genérica a evento y operación. Así, la formalización de OASIS está basada en la idea de ocurrencia de acciones en la vida de los objetos. Se asume por defecto que por cada acción a en la signatura de la clase, además existe ¬a representando la no-ocurrencia de dicha acción. En un instante determinado, una acción ocurre en un objeto si se provee un servicio o si se requiere un servicio de otro objeto (o a sí mismo). Del mismo modo, la no-ocurrencia de una acción en un objeto acontece cuando no se provee un servicio o cuando no se requiere un servicio en un cierto instante. Una acción establece una comunicación entre un cliente y un servidor. Siendo a la acción hCliente, Servidor, Servicioi, cada vez que en el objeto Cliente se activa una obligación asociada a la fórmula φ[¬a]false, la acción a debe acontecerle. Asociada a la ocurrencia de dicha acción en el cliente, en el objeto Servidor ocurrirá a ó ¬a según las fórmulas de prohibición definidas sobre a. Si en el servidor, para alguna de sus fórmulas ¬φ[a]false se cumple que |=w ¬φ, entonces ocurre ¬a, en caso contrario (|=w φ) ocurre a, siendo w el mundo en el que está el objeto. Nótese que la ocurrencia o no-ocurrencia de acciones (tanto en el cliente como en el servidor) depende de sus respectivos estados (mundos) en el instante de requerir y de proveer el servicio, respectivamente. El instante en el cual se provee el servicio es igual o posterior al instante en el que se requiere el servicio. 76 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS Cliente Servidor ocurre a ocurre a o -a Figura 6.7: Representación del mecanismo action sending. En OASIS se dispone de cuatro mecanismos de comunicación. Cada uno de ellos está caracterizado por los siguientes aspectos: Síncrono vs. asíncrono. La comunicación será síncrona si el cliente de la acción a debe esperar hasta conocer si en el servidor ocurre a o ¬a. Un caso especial de comunicación síncrona se produce cuando el servidor es el que debe esperar a que en el cliente ocurra (se genere) una determinada acción (la solicitud de servicio hacia el servidor). Cuando la comunicación es síncrona existe una acción indicando la ocurrencia o no-ocurrencia de la acción esperada. La comunicación será asíncrona si no existe espera asociada. Ocurrencia forzada vs. ocurrencia no forzada. La comunicación es de ocurrencia forzada para una acción a si su ocurrencia debe producirse tanto en el cliente como en el servidor, o en ninguno de ellos. 6.2.1. Mecanismos de comunicación Los mecanismos de comunicación disponibles en OASIS son: action sending, action waiting, action calling y action sharing, los cuales se describen a continuación. Action sending: asíncrono, ocurrencia no forzada. Este mecanismo se basa en la noción de obligación en el cliente. Sucede cuando es obligatoria la ocurrencia de una acción y el objeto en cuestión es el cliente de dicha acción. La Figura 6.7 ilustra este mecanismo1 . 1 En todas las figuras mostradas en este apartado las líneas verticales representan el paso del tiempo de arriba hacia abajo. Si la línea es continua indica que el objeto no está en espera. Si la línea es punteada indica que el objeto está en espera. 6.2. UN NUEVO ESQUEMA DE COMUNICACIÓN Servidor 77 Cliente ocurre a ocurre a Figura 6.8: Representación del mecanismo action waiting. Ejemplo 29 En la especificación del objeto controlador(número,[1]) se tiene la siguiente fórmula de obligación: nivel > max [¬valvula(nombre,[‘‘entrada’’])::cerrar] false Cuando se satisface nivel>max, al objeto cliente controlador debe acontecerle la acción: <self,valvula(nombre,[‘‘entrada’’]),cerrar> En un instante igual o posterior al actual, al objeto servidor valvula(nombre,[‘‘entrada’’])y de acuerdo con su estado, le acontecerá: <controlador(número,[1]), valvula(nombre,[‘‘entrada’’]),cerrar> o simplemente no ocurre dicha acción por no ser admitida. Action waiting: síncrono, ocurrencia forzada. Este mecanismo también se asocia a la noción de obligación. A diferencia del action sending, el objeto en el cual se obliga a que ocurra la acción no es el cliente de la acción sino el servidor. Es decir, el servidor está obligado a esperar que ocurra la acción en el cliente. La Figura 6.8 ilustra este mecanismo. Ejemplo 30 En la especificación del objeto sensor(tipo,[‘‘nivel’’]) se tiene la siguiente fórmula de obligación: conectado=false [¬controlador(someone):set(temperatura)] false Cuando en dicho objeto se satisface conectado=false es obligatorio que le acontezca la acción: <controlador(someone), 78 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS Servidor Cliente Servidor Cliente ocurriría a? ocurriría a? ocurre -a ocurre a ocurre -a ocurre a (a) (b) Figura 6.9: Representación del mecanismo action calling. sensor(tipo,[‘‘nivel’’]),set(temperatura)> Por tratarse de una obligación sobre un servicio provisto, el objeto servidor sensor esperará hasta que ocurra la acción asociada. Al implantar este tipo de interacción existiría la posibilidad de establecer un timeout por defecto, un tiempo máximo durante el cual la obligación puede afectar al servidor, es decir, cuánto tiempo esperará el servidor para recibir cierta solicitud de servicio desde un cliente. Una vez alcanzado el timeout, en el servidor ocurriría ¬a. Manipulando directamente el tiempo en la fórmula que define la obligación podría también especificarse un timeout arbitrario. Por ejemplo, redefiniendo el caso anterior con un timeout de 10 segundos: (currenttime2 -timeinicio) 6 10 and conectado=false [¬controlador(someone):set(temperatura)] false Siendo timeinicio un atributo de dominio time afectado por alguna evaluación asociada a una acción de obligación por satisfacerse conectado=false. Del mismo modo, mediante las pertinentes evaluaciones y obligaciones podría representarse el hecho de alcanzar el timeout sin haberse cumplido la obligación. Action calling: síncrono, ocurrencia forzada. Este mecanismo establece que una acción ocurre en el cliente y en el servidor o en ninguno de ellos. La Figura 6.9 ilustra este mecanismo. En la imagen (a) la acción a ocurre en el cliente y en el servidor, en la imagen (b) la acción a no ocurre en ninguno de ellos. 2 Asumiremos que currenttime es un atributo de dominio time, implícito para cada objeto y que representa la fecha y hora actual. Este atributo se ve afectado por cada tick del reloj. 6.2. UN NUEVO ESQUEMA DE COMUNICACIÓN 79 Ejemplo 31 En la especificación de la clase coche (clase agregada) se tiene la siguiente interacción con su objeto componente de la clase motor: arrancar ⇒ motor.encender Así, una acción con el servicio arrancar sólo ocurre si también ocurre la acción con el servicio encender en el objeto componente motor. Action sharing: síncrono, ocurrencia forzada. Una interacción action sharing se produce cuando acciones en distintos objetos y asociadas a proveer un servicio deben ocurrir todas o ninguna de ellas. Esta comunicación implica una sincronización entre objetos servidores. Ejemplo 32 En la especificación de la clase préstamo se tiene la siguiente interacción con sus componentes de la clase libro y de la clase socio: prestamo.prestar(Fecha,Socio,Libro) ⇔ libro(codigo,[Libro]).ser_prestado(Fecha) prestamo.prestar(Fecha,Socio,Libro) ⇔ socio(numero,[Socio]).obtener_libro Así, una acción con el servicio prestar(Fecha,Socio,Libro) sólo ocurre en el objeto préstamo si también ocurren las acciones con el servicio ser_prestado(Fecha) en el objeto componente libro(código,[Libro]) y la acción obtener_libro en el objeto componente socio(número,[Socio]), y viceversa. Como la comunicación action sharing es de ocurrencia forzada, para que cualquiera de las tres acciones ocurra deben ocurrir también las otras dos restantes. 6.2.2. Comentarios adicionales Mediante la combinación de action sending y action waiting es posible modelar cualquier interacción entre objetos pues ambas son primitivas elementales de comunicación. Sin embargo, para simplificar la especificación se proporcionan los mecanismos action calling y action sharing que establecen interacciones más complejas en un nivel adecuado de abstracción, resultando especialmente útiles para comunicación síncrona y de ocurrencia forzada entre un objeto agregado y sus objetos componentes. Al especificar una interacción particular entre objetos, los mecanismos de comunicación disponibles son distintos dependiendo de qué clase se está especificando: la clase del cliente o la clase del servidor. Si se está especificando la clase del objeto cliente para una determinada acción, los mecanismos de comunicación disponibles son: action sending y action calling. Si se está especificando la clase del objeto servidor para dicha acción, los mecanismos de comunicación disponibles son: action waiting y action sharing. 80 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS Cliente Servidor ocurre request ocurre request ocurre reply ocurre reply Figura 6.10: Representación de una interacción call/return Una interacción del tipo request/reply o call/return (Remote Procedure Call en arquitecturas distribuidas) puede ser especificada combinando una comunicación action sending con una action waiting, tal como se ilustra en la Figura 6.10. 6.3. Arquitecturas software en el marco de OASIS Arquitecturas Software [25] es un interesante enfoque para la construcción de sistemas de información. La clave de esta propuesta se resume en la idea razonable de no comenzar a construir un sistema desde cero, sino que aprovechar componentes disponibles e integrarlos en el nuevo sistema. Esta filosofía puede aplicarse a cualquier abstracción establecida de camino a la solución, es decir, la especificación de requisitos, diseño o implementación. El enfoque de Arquitecturas Software es ortogonal al enfoque Orientado a Objetos, sin embargo, constituyen una buena combinación que permite por un lado implementar de forma más directa y natural la filosofía de Arquitecturas Software y a la vez hacer más efectiva la tecnología Orientada a Objetos. Durante la elaboración de un nuevo esquema de interacción entre objetos en OASIS, se analizó la conveniencia de incorporar la filosofía de Arquitecturas Software. Este apartado describe las principales consideraciones asociadas. Finalmente, debido a la magnitud del cambio involucrado se decidió postergar para una siguiente versión esta alternativa. Una restricción que estaba presente era el asegurar una cierta continuidad y compatibilidad de la nueva propuesta respecto de la existente, intentando realizar mejoras basadas en extensiones. La introducción de la perspectiva cliente constituía en sí misma un cambio considerable respecto a la versión 2.2 de OASIS, añadir la filosofía de Arquitecturas Software equivalía a introducir la perspectiva cliente y bastante más. 6.3. ARQUITECTURAS SOFTWARE EN EL MARCO DE OASIS 6.3.1. 81 Componentes y conectores en OASIS Los conceptos clave en Arquitecturas Software son componentes y conectores. Los componentes disponen de puertos mediante los cuales pueden proveer o requerir servicios. Los conectores establecen enlaces (attachements) entre los puertos de componentes. En OASIS 3.0 el concepto de componente podría coincidir naturalmente con el de clase (sea una clase simple o compleja). En OASIS 3.0 el enlace entre clases puede establecerse de tres formas: en interfaces, mediante relaciones cliente-servidor explícitas en las acciones o por medio de agregaciones. Así, una interfaz determina que servicios puede un objeto cliente requerir de un objeto servidor. Alternativamente, en el cliente se especifica el servidor de una acción y en el servidor se puede especificar el cliente de una acción. Por otra parte, una agregación determina una relación estructural y de comportamiento entre el objeto agregado y sus objetos componentes, particularmente respecto de los servicios provisto y requeridos, una relación de agregación involucra enlaces entre acciones en el agregado y acciones en sus componentes y viceversa. Un primer problema a resolver para que una clase OASIS 3.0 coincida con el concepto de componente es prescindir de la definición explícita de los clientes y servidores de las acciones en la especificación de una clase. Es decir, en una especificación de clase no indicar a qué objeto se le provee un servicio ni a qué objeto se le requiere un servicio. En el caso de los clientes, siempre es posible prescindir del cliente en una acción. Si no se especifica el cliente significa que puede ser cualquier objeto que tenga acceso al servicio mediante una especificación de interfaz. En el caso que interese establecer diferencias de comportamiento para el mismo servicio pero solicitado por distintos clientes, se sugiere reemplazar el servicio original por dos servicios distintos cuya accesibilidad queda determinada en interfaces diferentes. Prescindir de los servidores es sólo posible cuando el servidor es el mismo objeto, es decir, cuando se trata de acciones asociadas a proveer un servicio, pero cualquier acción asociada a requerir un servicio debe incluir la declaración del objeto servidor. Prescindir de la definición de clientes y servidores permitiría que una clase OASIS pueda ser utilizada sin modificaciones en diferentes contextos, interactuando con otras clases. Es importante destacar que aunque en OASIS un componente siempre estaría representado por una clase (simple o compleja), no necesariamente todas las clases deben ser tratadas como componentes. Según esto, un componente en OASIS podría contener clases que dependen del contexto del componente, aunque el componente como un todo no depende del contexto. Sin embargo, dejar esta libertad en OASIS obligaría a introducir en forma no homogénea el concepto de componente, complicando el modelo. A continuación se propone un esquema de interacción para OASIS basado en Arquitecturas Software, en el cual el concepto de componente se aplica 82 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS uniformemente a todas las clases. El concepto de acción como tupla < Cliente, Servidor, Servicio > se reduciría a: acción asociada a Servicio provisto y acción asociada a Servicio requerido. Si en una especificación de clase OASIS no se especifican ni clientes ni servidores entonces toda acción de requerir un servicio debería estar explícitamente declarada como un servicio adicional en la signatura de la clase. Estos servicios serían solicitados por el objeto a sí mismo mediante obligaciones (disparos u transiciones en una operación). Complementariamente, se propone ampliar el mecanismo de interfaz, convirtiéndolo en el concepto de conector, utilizado en Arquitecturas Software. Una interfaz en OASIS establece relaciones de visibilidad y acceso de un cliente respecto de un servidor. Así, un conector establecerá relaciones de ocurrencia entre acciones en el cliente (por requerir un servicio) respecto de acciones en el servidor (por proveer un servicio). Estas relaciones de ocurrencia corresponden a los attachements definidos entre puertos de componentes. Un attachment se expresaría como: Acción_en_Cliente MC Acción_en_Servidor, donde MC es el mecanismo de comunicación utilizado. Los mecanismos de comunicación disponibles en OASIS se especificarían en cada attachement, y serían: Action waiting: Acción_en_Cliente ->? Acción_en_Servidor (el servidor está obligado a esperar hasta que el cliente solicite el servicio). Action sending: Acción_en_Cliente -> Acción_en_Servidor (comunicación asíncrona, en el servidor puede ocurrir la Acción_en_Servidor o una acción asociada a su rechazo) Action calling: Acción_en_Cliente =>> Acción_en_Servidor (la acción ocurre en el cliente y en el servidor o en ninguno de los dos, el cliente es el que genera la comunicación) Un caso particular se presenta en el mecanismo action sharing mediante el cual se establece un attachement entre objetos por proveer un servicio, es decir, entre objetos actuando como servidores. Action sharing: Acción_en_Servidor1 == Acción_en_Servidor2 (la acción ocurre en todos los servidores que la comparten). Cuestiones por resolver: 1. ¿Un conector debería ser tratado uniformemente como una clase?. La respuesta es NO. Aunque pareciera interesante llegar a establecer propiedades de plantilla y relaciones de herencia o agregación entre conectores, aparecen los siguientes inconvenientes: 6.3. ARQUITECTURAS SOFTWARE EN EL MARCO DE OASIS 83 - Los attachements entre acciones del cliente y servidor es una sección de especificación que no existe en una plantilla de clase OASIS y sólo sería necesaria para clases que representaran a un conector. - No tiene sentido hablar de instancias de conector, su creación o destrucción. Si un conector fuera relevante en cuanto a propiedades, debería modelarse como una clase adicional, con sus respectivos conectores a las clases que originalmente conectaba. - No parece interesante pensar en reutilización de conectores pues precisamente son lo que determinan a un sistema en particular. Esto no impide que los componentes que sean clases agregadas sean reutilizados incluyendo todos los conectores internamente definidos. 2. ¿Cuántas clases pueden relacionarse usando el mismo conector? La respuesta no parece tan evidente. La cuestión habría que resolverla pensando en que tipo de relación de comunicación se desea modelar en un conector. Por ejemplo, si sólo se trata de establecer attachements, una alternativa extrema podría ser definir sólo un conector para todo el sistema. Si se trata de particularizar interacciones entre ciertos componentes sería recomendable establecer un conector para cada grupo de participantes en una interacción de interés. 6.3.2. Un ejemplo aplicando arquitecturas software en OASIS A continuación se muestra el ejemplo de la máquina de venta de chocolatinas (presentado en el capítulo 5), el cual ha sido modificado (incluyendo cambios sintácticos) para incorporar las ideas asociadas a Arquitecturas Software planteadas antes. class vm identification number:(number); constant attributes number:nat; variable attributes num_chocs:nat; credit:nat; switch_on:bool(false); events3 set new; 3 En la signatura de eventos se incluyen explícitamente como eventos adicionales los eventos asociados a requerir un servicio (para facilitar la lectura, estos se han prefijado con “req_”. Es importante destacar que particularmente cuando un objeto puede requerir un servicio a sí mismo existen dos eventos diferentes involucrados: el primero correspondiente a 84 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS get_coin; give_choc; give_coin; light_empty; req_give_choc; req_give_coin; req_light_empty; operations cancel_button: S1 = {credit>1}req_give_coin.S1 + {credit<=1}req_give_coin; choc_button: S1 = req_give_choc; triggers req_light_empty when {nchocs=0 and switch_on=false}; valuations [get_coin] credit=credit+1; [req_give_coin] credit=credit-1; [req_give_choc] nchocs=nchocs-1, credit=credit-1; [req_light_empty] switch_on=true; preconditions choc_button if {credit>0 and nchocs>0}; cancel_button if {credit>0}; protocols getchoc: G1 = get_coin.G2; G2 = get_coin.G3 + choc_button.G1 + cancel_button.G1; G3 = get_coin.G4 + choc_button.G2 + cancel_button.G1; G4 = choc_button.G3 + cancel_button.G1; end class class customer identification name:(name); constant attributes name:string; events birth new; good_bye destroy; req_put_coin; req_push_cancel; req_push_choc; get_coin; requerir el servicio y el segundo está asociado a proveer el servicio. Por esta razón, aunque en el ejemplo los eventos give_choc, give_coin y light_empty no afectan al objeto, ellos son requeridos cuando acontecen los correspondientes eventos prefijados con req_. 6.4. CONCLUSIONES DEL CAPÍTULO 85 get_choc; end class connector among vm, self 4 attachements req_give_coin -> give_coin; req_give_choc -> give_choc; req_light_empty -> light_empty; end connector connector among customer alias C, vm alias VM attachements C:req_put_coin -> VM:get_coin; C:req_push_choc -> VM:choc_button; C:req_push_cancel -> VM:cancel_button; VM:req_give_coin -> C:get_coin; VM:req_give_choc -> C:get_choc; end connector 6.4. Conclusiones del capítulo El nuevo esquema de comunicación propuesto constituye una mejora para OASIS en términos de precisión y expresividad. Se han establecido cuatro tipos de comunicación que permiten modelar directamente la mayoría de los tipos de interacción más frecuentes entre objetos. Este esquema de comunicación ha sido adoptado en OASIS 3.0. Por otra parte, se presentaron las bases para la incorporación de las ideas de Arquitecturas Software en el marco de OASIS. Aunque este último enfoque resulta interesante se ha postergado su incorporación en OASIS 3.0 para mantener la compatibilidad con OASIS 2.2. 4 Se trata de un conector de un objeto de la clase vm consigo mismo, representando la comunicación self de los objetos de la clase vm. 86 CAPÍTULO 6. INTERACCIÓN ENTRE OBJETOS Capítulo 7 Un ejemplo en OASIS 3.0 Se ha preferido poner en un capítulo separado el ejemplo que se utilizará en los capítulos posteriores. Se trata de la especificación OASIS 3.0 para un sistema bancario “de juguete”. Este ejemplo no incluye la expresividad abordada en todos los aspectos de OASIS abordados en este trabajo, sin embargo, es representativo respecto de la animación automática implementada. conceptual schema simple_banking_system class account identification number:(number); constant attributes number:nat; name:string; variable attributes balance:int(0); times:nat(0); pin:nat(0); rank:nat(0); derived attributes good_balance:bool; derivations good_balance:={balance>=100}; events open new; close destroy; deposit(Amount:nat); withdraw(Pin:nat,Amount:nat); pay_commission; change_pin(Pin:nat,NewPin:nat); change_rank(Rank:nat); valuations [deposit(Amount)] balance:=balance+Amount, times:=times+1; [withdraw(Pin,Amount)] balance:=balance-Amount, times:=times+1; 87 88 CAPÍTULO 7. UN EJEMPLO EN OASIS 3.0 [pay_commission] balance:=balance-1; [::pay_commission] times:=0; [change_pin(Pin,NewPin)] pin:=NewPin; [change_rank(Rank)] rank:=Rank; preconditions withdraw(Pin,Amount) if {(pin=Pin and balance>=Amount) or (pin=Pin and balance<Amount and rank=2)}; change_pin(Pin,NewPin) if {pin=Pin}; close if {balance=0}; triggers ::pay_commission when {times>=5 and good_balance=false and rank=0}; end class class customer identification name:(name); constant attributes name:string; events add new; remove destroy; end class interface customer(someone) with account(someone) services(deposit,withdraw,change_pin,change_rank); end interface interface account(someone) with self services(pay_commission); end interface end conceptual schema En este ejemplo hay dos clases: customer y account. Los objetos de ambas clases son activos. Un objeto de la clase account está obligado a disparar a sí mismo una acción con el evento pay_commission cada vez que la condición de disparo se satisface. Aunque los objetos de la clase customer no tienen disparos explícitamente definidos, ellos tienen una definición de interfaz con objetos de la clase account permitiéndoles requerir acciones asociadas a los eventos visibles según la interfaz. Por esto, los objetos de la clase customer también son activos. Además, por defecto, existirá un objeto denominado root. Este objeto será responsable de activar los eventos que no tienen un cliente explícito en la especificación. En el ejemplo, el objeto root puede requerir acciones con los eventos add y remove de la clase customer. Capítulo 8 Un modelo de ejecución para OASIS En este capítulo se presenta un modelo de ejecución para la animación de especificaciones OASIS 3.0. La estructura y el comportamiento de un objeto están determinados por la clase de la cual es instancia y las relaciones que ésta tenga con otras clases. En particular, tal como se estableció en el capítulo anterior, el comportamiento de los objetos de una clase puede ser uniformemente expresado por un conjunto de fórmulas en la variante de lógica dinámica usada por OASIS. Dichas fórmulas definen tres aspectos del comportamiento: obligaciones, permisos (prohibiciones) y cambios de estado. Así, el modelo presentado permitirá animar las fórmulas que caracterizan el comportamiento de un objeto, entendido como una entidad autónoma, independiente y en concurrencia con otros objetos. Se utilizará como punto de referencia el modelo ACTORS [1]. 8.1. El modelo de ACTORS ACTORS es un modelo de computación concurrente para sistemas distribuidos. ACTORS no es por naturaleza un modelo que usa el paradigma de objetos, pero ofrece un marco útil para el diseño de un modelo de ejecución asociado al enfoque orientado a objeto. Los actores son agentes computacionales los cuales establecen correspondencias entre comunicación recibida respecto de una terna compuesta por: Un conjunto finito de comunicaciones enviadas a otros agentes. Un nuevo comportamiento que gobernará el procesamiento de la próxima comunicación. 89 90 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS Un conjunto finito de nuevos actores creados. Cada actor tiene un tiempo (reloj) local el cual permite ordenar linealmente las comunicaciones de acuerdo a cuándo éstas ocurren en el agente, o alternativamente permite ordenar los estados del agente. Se asume en general un entorno distribuido asincróno, desde el cual la necesidad de una interacción sincróna puede ser derivada como un caso especial. Cada actor posee un buzón que almacena las comunicaciones a ser procesadas. Cuando un actor Xn acepta la n-ésima comunicación almacenada en el buzón, se crea un nuevo actor Xn+1 , resultante del reemplazo de comportamiento del actor anterior. Todo el cómputo en un sistema de actores se produce en respuesta a comunicaciones. Las comunicaciones están contenidas en tareas. A medida que el cómputo avanza, un actor evoluciona para incluir nuevas tareas y nuevos actores que son creados como resultado del procesamiento de tareas. Las tareas ya procesadas y los actores que ya no serán útiles son eliminados del sistema. La configuración de un sistemas de actores está definida por los actores que contiene así como por las tareas no terminadas de procesar. Una tarea consiste en: una etiqueta que la distingue de todas las otras tareas del sistema, la dirección del buzón hacia el cual debe enviarse la comunicación y la comunicación en sí, incluyendo información para el actor receptor. Hay tres formas en las cuales un actor, al aceptar una comunicación, puede saber la dirección del buzón hacia el cual debe enviar una determinada comunicación: el actor lo sabía antes de recibir la comunicación, la dirección está incluida en la información de la comunicación recibida o se trata del buzón de un actor creado como resultado de la comunicación recibida. La Figura 8.1 ilustra los aspectos básicos del modelo ACTORS. Partiendo de la proximidad entre los conceptos de actor y de objeto (en OASIS) pueden establecerse las siguientes correspondencias: Concepto ACTORS comunicación recibida tarea buzón reemplazo del comportamiento creación de actor Concepto OASIS acción asociada a proveer un servicio acción asociada a requerir un servicio1 acciones de servicio en orden de llegada cambio de estado creación de un nuevo objeto En el marco de OASIS es necesario además tener en cuenta las siguientes consideraciones: 1 Se trata de una acción asociada a una obligación y en la cual el cliente es el propio objeto. 8.1. EL MODELO DE ACTORS 1 91 n n+1 2 ... ... transición (reemplazo) Xn tarea producida Xn+1 creación de un nuevo actor 1 2 ... tarea Y1 Figura 8.1: Representación de aspectos básicos de un actor Tanto las acciones asociadas a proveer un servicio como las asociadas a requerirlo deben ser tratadas uniformemente pues ambas pueden afectar el estado del objeto. De esta forma la perspectiva servidor y la cliente son tratadas de forma homogénea. Lo anterior determina que el buzón incluya también las acciones asociadas a requerir un servicio. En un mismo instante a un objeto le puede ocurrir más de una acción. En OASIS un objeto cambia de estado por la ocurrencia de un paso (conjunto consistente de acciones). Cada paso incluye al menos todas las acciones asociadas a obligaciones y cuya condición se satisface en el estado actual del objeto, además un paso podría incluir acciones de servicio que no estén en conflicto entre ellas ni con las acciones por obligación. Nótese que las obligaciones asociadas a requerir un servicio ya han sido contempladas en el punto anterior. Sin embargo, aquellas obligaciones que determinan una acción de proveer un servicio (cuando el cliente de la acción es otro objeto) son acciones que puede que no estén presentes en el buzón en el momento de generarse la obligación. Esta situación es en sí el mecanismo de comunicación action waiting de OASIS. OASIS ofrece cuatro mecanismos de comunicación: action sending, action waiting, action calling y action sharing. El mecanismo action send- 92 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS ing, por tratarse de un mecanismo asíncrono, está directamente representado por el procesamiento de acciones de proveer servicio y de acciones de requerir un servicio, de las cuales sólo son obligaciones las últimas. El mecanismo action waiting, tal y como se indicó antes, implica una sincronización de espera pues el objeto está obligado a proveer un servicio cuyo cliente es otro objeto. Los mecanismos primitivos de comunicación son action sending y action waiting, de esta forma, los mecanismos action calling y action sharing pueden definirse usando los primeros. La ocurrencia de acciones de servicio puede ser descartada en caso que no se satisfagan los permisos definidos. La creación de un objeto es una actividad reservada sólo a objetos especiales, aquellos que representan a una clase2 . 8.2. Un modelo abstracto para animación en OASIS El modelo abstracto de ejecución establece el vínculo entre la semántica de una especificación OASIS y una implementación concreta en un entorno de programación. El modelo debe ser descrito con suficiente precisión para evitar ambigüedades en su implementación. Establecer un modelo abstracto de ejecución implica separar las consideraciones que definen al modelo de otras propias de la implementación del mismo en el entorno de programación utilizado. Sin embargo, respecto del enfoque de implementación esperado, el modelo abstracto de ejecución tendrá una orientación a priori, la cual se establece a continuación. En la Figura 8.2 se clasifican diferentes enfoques de implementación para ejecución de especificaciones OASIS, desde la perspectiva del programa construido y dependiendo de si el entorno de programación es secuencial o concurrente. El eje horizontal mide el grado de secuencialidad/concurrencia ofrecida por el entorno y utilizada en la implementación. El eje vertical mide el grado de correspondencia entre los objetos de la especificación OASIS y su representación en el código del programa3 . En un entorno de programación secuencial debe siempre implementarse un monitor que simule la autonomía y concurrencia mediante la administración de la actividad del sistema. El mínimo trabajo que podría implementarse para 2 Como veremos más adelante, las clases en tiempo de ejecución son objetos que sirven acciones de creación de objetos (de dicha clase) y mantienen la asociación entre mecanismos de identificación de cada objeto y el respectivo oid. 3 Debido a las diferencias de conceptos entre los diversos lenguajes orientados a objeto y a su vez respecto de OASIS, no es imprescindible que el entorno de programación utilizado sea orientado a objeto. 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS + OO 93 ... Monitor ... Monitor Monitor ... ... - OO BD Secuencial BD Concurrente Figura 8.2: Entornos de programación para ejecución de especificaciones OASIS el monitor podría ser limitarlo a distribuir el hilo de ejecución entre los distintos objetos del sistema, manteniendo los aspectos de estructura y el resto de aspectos de comportamiento encapsulados en las implementaciones de los objetos. Esta situación se ilustra en el vértice superior izquierdo del gráfico de la Figura 8.2. En otro extremo, el monitor podría simular todo el comportamiento de los objetos, caso en el cual la implementación no guarda una correspondencia uno a uno respecto de los objetos. Esta situación se ilustra en los vértices inferiores del gráfico de la Figura 8.2. En el vértice inferior derecho de la Figura 8.2 la concurrencia ofrecida por el entorno de programación sólo es utilizada para implementar distintos aspectos del monitor, no relacionados directamente con objetos del sistema. Siendo el propósito fundamental en este trabajo la validación de requisitos expresados mediante una especificación OASIS, es indispensable mantener la implementación lo más cercana posible a la semántica de OASIS. De esta forma existirá un camino de formalización y verificación de la implementación obtenida respecto de la semántica de la especificación OASIS. Esto sugiere que la mejor alternativa es utilizar un entorno de programación concurrente y dotar de un hilo de ejecución a cada objeto, es decir, trabajar en el vértice superior derecho del gráfico de la Figura 8.2. Así, el modelo abstracto de ejecución que se plantea a continuación está orientado a entornos de programación concurrente. 94 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS 8.2.1. Alcance del modelo Desde el punto de vista de la semántica de OASIS, el modelo de ejecución no es más que un modelo para animar fórmulas de obligación, permiso y evaluación, asociadas a un objeto. En esta perspectiva, la información utilizada por el modelo es la signatura de atributos y acciones del objeto junto al conjunto de fórmulas en Lógica Dinámica que describen su comportamiento, incluyendo las especificaciones de proceso interpretadas también como fórmulas en la Lógica Dinámica utilizada. Cuando se trata con objetos de clases simples, esta información es precisamente la plantilla de la clase del objeto. Sin embargo, si la clase del objeto es compleja (por especialización o agregación) no toda la información está directamente en la plantilla de la clase del objeto. A pesar de esto, podemos suponer externo al modelo de ejecución el trabajo que determina la estructura y el comportamiento del objeto en el caso de objetos pertenecientes a clase complejas y así reducir el planteamiento del modelo de ejecución al caso de un objeto instancia de una clase simple. No serán incluidos dos aspectos del comportamiento del objeto: las restricciones de integridad y las operaciones etiquetadas como transacción. Sólo se abordarán los mecanismos básicos de comunicación: action sending y action waiting. Sin embargo, la extensión del modelo para incluir action calling y action sharing debe utilizar dichos mecanismos básicos. La creación y tratamiento de objetos complejos hace uso exhaustivo de los mecanismos action calling y action sharing, por consiguiente también los objetos complejos quedarán fuera del alcance de este trabajo. Por lo anterior, el modelo de ejecución excluye algunos casos de especificación y su correspondiente animación pero reduce el alcance del trabajo a proporciones y complejidad adecuadas. 8.2.2. Aspectos básicos La secuencia de pasos que le acontecen a un objeto está ordenada respecto del tiempo. Podemos suponer que existe un objeto “reloj” que envía acciones especiales —llamadas ticks- hacia cada objeto del sistema4 . Los ticks recibidos por un objeto son correlativos con los números naturales, t1 , t2 , etc. Sean i y j números naturales tal que i < j ⇐⇒ ti < tj . Definición 17 Buzón. Es el conjunto de acciones que pueden formar parte del paso que un objeto ejecuta en un determinado tick. El buzón en el instante ti se denota por Mboxi . Consideraremos el buzón como un buffer ilimitado, en el cual las acciones se ordenan por orden de llegada. 4 Para propósitos de animación en este punto no tiene mayor importancia el que el reloj sea sólo uno para todo el sistema, sea uno para cada objeto u otra alternativa. 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS Mboxi+1 Mboxi Statei-1 95 Statei ti Statei+1 ti+1 Figura 8.3: Ciclo de vida de un objeto Definición 18 Estado i-ésimo del objeto. Denotado por Statei , representa el estado del objeto en el intervalo (ti , ti+1 ] . Es decir, inmediatamente después de ti y hasta ti+1 inclusive, el estado se mantiene constante. La Figura 8.3 muestra un Diagrama de Vida de Objeto simplificado, el cual permite ilustrar el ciclo de vida de un objeto según las definiciones dadas. El conjunto de acciones en cada paso es obtenido desde el buzón de acciones del objeto y la ejecución del paso en un instante produce un cambio de estado, el cual no será observable hasta el siguiente tick. Así, en la estructura de tiempo utilizada aunque la ocurrencia de acciones es instantánea, los estados tienen una cierta duración. 8.2.3. Concurrencia intra-objeto Una cuestión que se plantea es ¿Se limita o no el número de acciones a ser ejecutadas en un determinado instante?, o en otras palabras: ¿Se permitirá concurrencia intra-objeto en el modelo de ejecución?. La concurrencia intraobjeto es imprescindible para una animación fiel a la semántica de OASIS. Básicamente dos situaciones justifican la incorporación de concurrencia intraobjeto en el modelo de ejecución: Cuando en un instante hay que ejecutar más de una acción (de acuerdo a las obligaciones establecidas), deben todas ellas realizarse en el mismo instante de lo contrario se contradice la semántica de la fórmula de obligación correspondiente. En el caso de objetos agregados, la ejecución concurrente de los objetos componentes en forma natural puede producir acciones concurrentes vistas desde el objeto agregado. 96 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS La definición de consistencia para un conjunto de acciones es de carácter general. Para obtener una implementación directa y sencilla que asegure la consistencia de las acciones en un paso a continuación se define el concepto de conflicto entre acciones. 8.2.4. Conflicto entre acciones Si se ejecuta más de una acción en un paso, tal como se plantea en [32], debería garantizarse la consistencia y la terminación, o al menos indicar al analista/diseñador que dichas propiedades no se pueden determinar con certeza en la especificación. El total de las acciones ejecutadas en un paso debería ser consistente5 , es decir, no debe existir conflicto respecto de las modificaciones que realizan las acciones sobre los atributos del objeto. Definición 19 Relación afecta. Sea Att el conjunto de atributos del objeto. Se define la relación afecta como: AfectaStatei ⊆ M boxi × Att Sea a1 ∈ Mboxi y att1 ∈ Att, diremos que a1 AfectaStatei att1 si y sólo si la ejecución de la acción a1 modifica6 el valor del atributo att1 en ti . Definición 20 Conflicto entre acciones. Sea Acc ⊆ Mboxi y Att el conjunto de atributos del objeto. Diremos que Acc tiene conflicto entre acciones si NO se satisface la siguiente condición: ∀a1 , a2 ∈ Acc y ∀att ∈ Att : [a1 Af ectaStatei att ∧ a2 AfectaStatei att] =⇒ a1 = a2 Definición 21 Conjunto consistente de acciones (versión modelo de ejecución). Sea Acc ⊆ Mboxi , diremos que Acc es consistente si no presenta conflicto entre sus acciones. Así, para garantizar la consistencia de un de un conjunto de acciones en el buzón bastará con asegurar que dichas acciones no están en conflicto. Esto puede detectarse automáticamente, basta con inspeccionar los conjuntos de atributos que pueden sufrir una asignación de valor para cada acción, revisando las evaluaciones asociadas a dicha acción. Los conjuntos de atributos 5 O sea, tener un comportamiento funcional: su resultado es siempre el mismo para un conjunto de acciones dadas, independiente del orden en el que se ejecuten. 6 La modificación puede ser indirecta en el caso de atributos derivados. Así, si att2 es un atributo derivado definido en función de att1 , entonces: a1 Af ectaStatei att1 =⇒ a1 Af ectaStatei att2 . 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS 97 obtenidos deben ser disjuntos para que el conjunto de acciones correspondiente sea consistente. Nótese que cuando existe conflicto entre acciones puede aún existir consistencia (según su definición original). Por ejemplo, consideremos las siguientes evaluaciones: att = V [a1 ]att = V + 1 att = V [a2 ]att = V + 2 En este caso, a1 y a2 están en conflicto pero al aplicar a1 y luego a2 el efecto es el mismo que al hacerlo en el otro orden, con lo cual a1 y a2 constituyen un conjunto consistente (según la definición de consistencia original). Sin embargo, la exclusión de casos como este no contradice la semántica de OASIS y facilita la determinación de los conjuntos de acciones que pueden ejecutarse en un paso. En [32] se plantean los problemas de terminación que pueden surgir al aplicar una a una las acciones de un paso, cambiando de estado en cada aplicación, lo cual podía a su vez generar nuevas acciones producto de obligaciones por cambio de estado. En nuestro caso, una vez seleccionado el conjunto consistente de acciones que forma el paso, se aplican todas las acciones a la vez, produciendo un sólo cambio de estado correspondiente al efecto de todas las acciones (sin inconvenientes gracias a que no existe conflicto entre ellas). Debido a este enfoque, la propiedad de terminación en el procesamiento de las acciones en un paso está siempre asegurada. 8.2.5. Clasificación de acciones en el buzón El procesamiento de las acciones del buzón implica clasificar las acciones contenidas en él. A continuación se presentan las categorías de acciones identificables en el buzón, caracterizadas como subconjuntos de Mboxi (es decir, en el instante ti ). Definición 22 Acciones de requerir. Es un subconjunto de M boxi constituido por acciones asociadas a obligaciones por requerir un servicio (en las cuales el cliente es el propio objeto) y que deben acontecer. El conjunto de acciones de requerir en el instante ti se denota por OReqi . Las acciones de requerir están determinadas por fórmulas de obligación, es decir, de la forma: φ[¬a]false, en las cuales a =< self, Server, Service >, es decir, el cliente de la acción es el propio objeto, indicado usando la palabra self. Definición 23 Acciones obligadas de proveer. Es un subconjunto de Mboxi constituido por acciones correspondientes a servicios que el objeto debe proveer. 98 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS Estas acciones están asociadas a obligaciones, en las cuales el cliente no es el propio objeto. El conjunto de acciones obligadas de proveer en el instante ti se denota por OP rovi . Las acciones obligadas de proveer están determinadas por fórmulas de obligación, es decir, de la forma: φ[¬a]false, en las cuales una acción tiene la estructura siguiente: < Client, self, Service >, es decir, el servidor de la acción es el propio objeto, indicado usando la palabra self. Definición 24 Acciones obligadas. Es un subconjunto de Mboxi denotado por OExeci , tal que: OExeci = OReqi ∪ OP rovi . Supondremos que garantizar la no-existencia de conflicto entre acciones obligadas es parte de la verificación estática de la especificación. Es decir, en tiempo de ejecución no puede presentarse conflicto entre obligaciones7 . Del mismo modo, no debe darse una situación en la cual una acción obligada no está permitida. Definición 25 Acciones no-obligadas. Es un subconjunto de Mboxi constituido por acciones correspondientes a servicios solicitados por otros objetos (o por el propio objeto) y que el objeto puede proveer, dependiendo de los permisos establecidos sobre dichas acciones, verificados sobre Statei . El conjunto de acciones no-obligadas en el instante ti se denota por OExeci . Definición 26 Acciones rechazadas. Es un subconjunto de OExeci constituido por acciones no-obligadas cuya ocurrencia NO está permitida en el instante ti . El conjunto de acciones rechazadas se denota por Rejecti . Las acciones rechazadas están determinadas por fórmulas de prohibición, es decir, de la forma: ¬φ[a]false. La opción básica para el tratamiento de las acciones rechazadas es simplemente ignorarlas. Un tratamiento más elaborado podría ser, por ejemplo: Generar automáticamente una “acción de rechazo”, es decir, una acción de requerir dirigida hacia el cliente indicando el rechazo de su solicitud de servicio. Esto implica, desde el punto de vista del cliente, tener que considerar acciones implícitas de ”aviso de rechazo” por cada posible acción de solicitud de servicio. Mantener las acciones rechazadas como acciones no-obligadas que podrían ser ejecutadas en el próximo tick. Aunque esta alternativa no contradice la semántica del lenguaje introduce una relatividad no deseada Si se tienen las fórmulas φ1 [¬a1 ]f alse y φ2 [¬a2 ]f alse siendo a1 y a2 dos acciones en conflicto, entonces no debe existir un mundo w tal que |=w φ1 ∧ φ2 . 7 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS 99 respecto del comportamiento del objeto durante su ejecución. Además el crecimiento y manipulación de la acumulación de acciones rechazadas presenta inconvenientes obvios. Se optará por generar automáticamente acciones de rechazo. Estás serán registradas como acciones obligadas de requerir en el buzón del instante en el cual se produce su rechazo. Se trata de acciones cuyo cliente es el objeto que rechaza la ocurrencia de una acción y el servidor es el cliente de la acción rechazada, es decir, constituyen un aviso para un cliente cuando la acción es rechazada en el servidor. Definición 27 Acciones candidatas. Es un subconjunto de OExeci constituido por acciones no-obligadas cuya ocurrencia está permitida en el instante ti . El conjunto de acciones candidatas se denota por Candi . Además, se cumple que OExeci = Rejecti ∪ Candi . Definición 28 Acciones ejecutadas. Es el conjunto de acciones correspondiente al paso a ser ejecutado en un determinado instante. El paso en el instante ti será denotado por Execi . El paso estará constituido por OExeci (acciones obligadas) más un subconjunto de Candi , es decir, acciones noobligadas que están permitidas. La selección del subconjunto de acciones de Candi que serán incluidas en Execi puede responder a distintos criterios y la única restricción es que no se produzcan conflictos entre las acciones del paso. Definición 29 Acciones en conflicto. Es un subconjunto de Candi constituido por acciones no-obligadas cuya ocurrencia está permitida en el instante ti , pero que están en conflicto con alguna de las acciones obligadas o con alguna de las acciones no-obligadas seleccionadas. El conjunto de acciones en conflicto se denota por Confi . Utilizaremos un criterio sencillo para la selección de acciones desde Candi : ante dos acciones que no pueden ser seleccionadas por estar en conflicto se seleccionará aquella llegada antes al buzón. Este criterio evita postergación indefinida de acciones en conflicto. Las acciones en conflicto Confi serán copiadas al buzón correspondiente al siguiente instante (Mboxi+1 ). 8.2.6. Comunicación self La comunicación del objeto consigo mismo se produce cuando una acción obligada de requerir es dirigida hacia el mismo objeto (el servidor es self). 100 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS Esta comunicación es tratada de forma uniforme respecto del resto de comunicaciones, es decir, la acción obligada de requerir será posteriormente recibida en el buzón como una acción no-obligada (una solicitud de servicio). Según esto, en dicha situación se distinguen dos acciones: la acción de requerir el servicio a sí mismo (obligación) y la acción no-obligada de proveer dicho servicio. En general la segunda acción podría sufrir algún retraso y ser procesada en un intervalo de tiempo posterior. La primera por tratarse de una obligación no puede ser rechazada, la segunda sí. 8.2.7. Modelando el comportamiento interno del objeto El comportamiento de un objeto estará regido por un bucle de actividad interna. Esta actividad realiza la transición del objeto desde un estado inicial Statei a un estado final Statei+1 . Utilizaremos una acción implícita para representar los ticks e incluirlos homogéneamente dentro del buzón. Un tick corresponde a la acción representada por la tupla: < reloj, Object, tick(t, i) >. Object una referencia de objeto servidor que coincide con el propio objeto, es decir, se trata como una acción de servicio solicitada por “reloj”. t es el tiempo real correspondiente al i-ésimo tick. La separación real de tiempo entre tick y tick podría no ser constante. La Figura 8.4 ilustra los principales aspectos considerados en el modelo de ejecución. Un objeto transita desde el estado Statei hacia el estado Statei+1 por la ocurrencia del paso representado por Execi correspondiente a un subconjunto de acciones de Mboxi . La comunicación desde otros objetos (o desde el propio objeto) se representa por las flechas etiquetadas como OExeci y OExeci+1 . La comunicación hacia otros objetos se representa en la parte inferior de la Figura 8.4 por las flechas saliendo hacia buzones de otros objetos. Las flecha etiquetada con Confi representa las acciones en conflicto en ti , las cuales son copiadas al siguiente buzón. La flecha etiquetada con OExeci+1 representa las obligaciones de requerir que el objeto adquirirá en el instante ti+1 producto de la ocurrencia de las acciones Execi . Las clases en ejecución serán implementadas homogéneamente como objetos. Estos metaobjetos proveen el servicio de creación de objetos de la clase correspondiente. Por lo tanto, como ilustra la Figura 8.4 en su parte inferior derecha, si un metaobjeto ejecuta una acción de creación de instancias (acción new) dentro de su proceso de cambio de estado se incorporará la creación de un nuevo objeto, cuya primera acción ocurrida es la acción new. Cada M box se considera completo sólo cuando ha llegado la acción tick. Si el objeto termina el cambio de estado y aún no se recibe la acción tick, esperará hasta que esta llegue. Por el contrario, si objeto termina el cambio de estado 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS OExeci OExeci OExeci+1 OExeci+1 Confi Confi-1 Confi+1 Mboxi+1 Mboxi ... a1 a2 101 ... tick a3 a4 ti ... ... tick ti+1 Execi+1 Execi cambio de estado Statei Statei+1 Envío de acciones en OReqi a los servidores correspondientes Creación de un objeto (realizada sólo por objetos "clase") Mbox'j ... Mbox'''0 ... tick ... new ... Mbox''k ... ... tick ... State'''0 State'j State''k Figura 8.4: Vida de un objeto en OASIS y ha llegado más de una acción tick, sólo se considerará el último, los otros son ignorados. Nótese que la frecuencia de tick determina el tamaño del Mbox que se procesará, por lo tanto si se aumenta la frecuencia de ticks ( sin variar la frecuencia de acciones que llegan al Mbox) se puede llegar al extremo en el cual el buzón contiene sólo una acción además de la acción tick o incluso sólo la acción tick. Por otra parte, reduciendo la frecuencia de ticks el buzón tiene la posibilidad de contener mayor cantidad de acciones lo cual podría producir más acciones en conflicto. Cualquiera que sea el caso, la frecuencia de ticks y el ordenamiento de acciones del buzón representan el indeterminismo propio de los sistemas concurrentes. Sin embargo, la fidelidad respecto de la semántica de OASIS siempre se mantiene. La semántica de la comunicación action waiting exige un tratamiento especial. Aunque ya esté presente un tick para completar el Mbox el objeto no 102 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS puede alcanzar el nuevo estado si no están presentes las acciones obligadas de proveer (que precisamente corresponden a comunicación action waiting). Esto ocasionará una posible espera, en la cual podrán llegar nuevos ticks que serán ignorados. Sólo cuando todas las acciones obligadas de proveer están contenidas en el buzón y ha llegado un tick (en un instante posterior) el objeto procesará el buzón y alcanzará el estado siguiente. Finalmente, el siguiente algoritmo expresa la actividad interna de cada objeto durante su existencia: i=0 OP rovi = {} State0 ← {} REPETIR ESPERAR HASTA QUE (tick ∈ M boxi ∧ OP rovi ⊆ M boxi ) OReqi ← obtener_acciones_de_requerir(M boxi ) enviar_acciones_de_requerir(OReqi ) OExeci ← obtener_acciones_no_obligadas(Mboxi ) Rejecti ← calcular_acciones_rechazadas(OExeci , Statei ) Candi ← OExeci − Rejecti Confi ← calcular_acciones_en_conflicto(Candi , Statei ) Execi ← OReqi ∪ OP rovi ∪ (Candi − Confi ) Statei+1 ← determinar_nuevo_estado(Execi , Statei ) OP rovi+1 ← calcular_próx_accs_obligadas_de_proveer(Statei+1 ) OReqi+1 ← calcular_próx_accs_obligadas_de_requerir(Statei+1 ) M boxi+1 ← Mboxi+1 ∪ OReqi+1 ∪ Confi i =i+1 FIN_REPETIR Observaciones Las funciones “obtener_...” seleccionan subconjuntos de Mbox de acuerdo con las definiciones dadas. El procedimiento enviar_acciones_de_requerir se encarga de hacer llegar las acciones de requerir a los buzones de los respectivos servidores. Las funciones “calcular_...” utilizan además las fórmulas que definen el comportamiento del objeto (fórmulas de obligaciones, permisos y cambios de estado). La función determinar_nuevo_estado obtiene el estado siguiente utilizando además las fórmulas de cambio de estado. Mediante las definiciones y comentarios respecto de cada uno de los conjuntos involucrados todas las funciones pueden ser implementadas sin ambigüedad en el entorno de programación concurrente elegido. 8.2. UN MODELO ABSTRACTO PARA ANIMACIÓN EN OASIS asignar_categoria(0) reintegro(20) reintegro(10) ingreso(40) reintegro(30) Mbox1 Mbox2 asignar_categoria(0) x reintegro(20) reintegro(10) t1 saldo=10 veces=1 categoria=1 buen_saldo=false asignar_categoria(2) ::pagar_comision saldo=0 veces=2 categoria=0 buen_saldo=false Mbox3 ingreso(40) x reintegro(30) t2 cerrar ingreso(90) pagar_comision saldo=40 veces=3 categoria=0 buen_saldo=false t3 reintegro(70) Mbox4 asignar_categoria(2) :: pagar_comision Mbox5 x cerrar ingreso(90) pagar_comision saldo=40 veces=0 categoria=2 buen_saldo=false 103 reintegro(70) ingreso(90) t4 saldo=39 veces=0 categoria=2 buen_saldo=false t5 saldo=129 veces=1 categoria=2 buen_saldo=true self:pagar_comision Figura 8.5: Ciclo de vida de una instancia de cuenta entre t1 y t5 8.2.8. El modelo de ejecución en funcionamiento Usando el ejemplo de la cuenta bancaria, realizaremos una animación basada en el modelo de ejecución propuesto. La siguiente tabla muestra una posible secuencia de eventos recibida por un objeto de la clase cuenta. Intervalo (ti−1 − ti ] (... − t1 ] (t1 − t2 ] (t2 − t3 ] (t3 − t4 ] (t4 − t5 ] Acciones contenidas en Mboxi asignar_categoria(0) reintegro(20) reintegro(10) ingreso(40) reintegro(30) asignar_categoria(2) ::pagar_comision pagar_comision ingreso(90) cerrar reintegro(70) La Figura 8.5 muestra un Diagrama de Vida del Objeto en el cual se detalla parte del ciclo de vida de un objeto (entre los instantes t1 y t5 ). Para esta instancia de la clase cuenta, consideraremos que su estado actual (justo antes de t1 ) es: State0 = {< num, 1010 >, < nombre, juan >, < saldo, 10 >, < veces, 1 >, < categoria, 1 >, < buen_saldo, false >} 104 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS El eje horizontal representa el tiempo de izquierda a derecha. Bajo el eje del tiempo se indican los valores de atributos variables del objeto. Entre (ti − ti+1 ] el estado del objeto no cambia. Sobre el eje del tiempo y bajo los rectángulos se indica los cambios que sufrirán los atributos variables y que se reflejarán en el siguiente ti . Los rectángulos representan el buzón (Mboxi ) y su contenido en cada tick. El símbolo “X”delante de una acción en el Mboxi indica que está permitida en dicho instante, el símbolo “x” delante de una acción indica lo contrario. Las acciones en conflicto han sido subrayadas. Las acciones no-obligadas recibidas entre (ti − ti+1 ] están representadas en las flechas descendientes entre Mboxi y Mboxi+1 . La flecha ancha inferior representa acciones obligadas de requerir. Comentarios respecto del ejemplo Después de t2 , y sabiendo que en t3 será satisfecha la obligación que produce una acción por requerir el servicio pagar_comision, es generada automáticamente la correspondiente acción de requerir en Mbox3 . En t3 se tiene en el buzón una acción de requerir asociada a la obligación de solicitar a sí mismo el servicio pagar_comision. Posteriormente, se recibe como la correspondiente acción de solicitud de servicio y es ejecutada en t4 . En t4 y t5 el buzón contiene acciones que están en conflicto pues el atributo saldo puede ser modificado por más de una acción. En t4 la acción cuyo servicio es ingreso(90) está en conflicto con la acción cuyo servicio es . Así, la acción cuyo servicio es ingreso(90) es postergada hasta el siguiente tick, siendo copiada a Mbox5 . En t5 la acción cuyo servicio es ingreso(90) forma un conjunto inconsistente con la acción cuyo servicio es reintegro(20). En este caso, esta última acción se ha considerado en conflicto, y se ha copiado en el siguiente buzón. 8.3. Conclusiones del capítulo Se ha presentado el modelo de ejecución que permite animar especificaciones OASIS 3.0. En OASIS el comportamiento de un objeto es formalizado en una variante de Lógica Dinámica y se expresa como un conjunto de fórmulas que representan obligaciones, permisos y cambios de estado. Así, el modelo de ejecución planteado es un animador para este tipos de fórmulas. Este modelo es una base sólida para trabajos de animación de especificaciones OASIS fieles a la semántica del modelo OASIS. El modelo puede 8.3. CONCLUSIONES DEL CAPÍTULO 105 ser extendido para incluir aspectos más complejos del comportamiento, tales como: restricciones de integridad, operaciones etiquetadas como transacción, comunicación usando action calling y action sharing, y por último objetos complejos. 106 CAPÍTULO 8. UN MODELO DE EJECUCIÓN PARA OASIS Capítulo 9 Programación Lógica Concurrente En este capítulo se hace una introducción al paradigma de Programación Lógica Concurrente (PLC). Se describen las principales características de este paradigma y se compara con la Programación Lógica clásica. Posteriormente se analizan las capacidades de la Programación Lógica Concurrente para el modelado de comunicación entre procesos, desarrollando varios ejemplos en PARLOG. Finalmente se presentan los elementos básicos para la representación de clases y objetos en Programación Lógica Concurrente. La Programación Lógica Concurrente surge como un intento de mejorar la eficiencia de los lenguajes lógicos mediante el uso del paralelismo AND de flujo. Además, son lenguajes de alto nivel muy convenientes para sistemas paralelos y distribuidos. El nombre de concurrentes para este tipo de lenguajes lógicos, los distingue de otros intentos por construir un PROLOG paralelo. La diferencia radica en la distinción que se establece entre dos tipos de sistemas o programas: transformacionales y reactivos (interactivos) [85]. Un sistema transformacional recibe un entrada al comienzo de su ejecución y devuelve un resultado al final, el propósito de los sistemas reactivos no es, necesariamente, obtener un resultado final, sino mantener un interacción con el entorno. De hecho, los sistemas reactivos más usuales (sistemas operativos, sistemas de administración de bases de datos) nunca terminan. PROLOG fue diseñado desde un punto de vista transformacional y, aunque contiene algunas características de entrada/salida básicas, usualmente no están integradas en su modelo de cómputo. Por el contrario, los lenguajes lógicos concurrentes responden mejor al modelo reactivo, aunque esto no descarta su conveniencia en aplicaciones que son transformacionales por naturaleza. Es decir, aunque un sistema concurrente (lógico o no) sea de forma global transformacional o reactivo, sus componentes pueden verse como reactivas, ya que 107 108 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE tienen una interacción continua entre sí y posiblemente también con el entorno. De este modo, todos los sistemas concurrentes, independientemente de la razón por la que explotan la concurrencia, tienen un aspecto en común: el lenguaje en el que se implementan necesitan especificar procesos reactivos, su creación, interconexión, comportamiento interno, comunicación y sincronización. Del mismo modo que los programas lógicos admiten una interpretación basada en procedimientos, también admiten una lectura basada en procesos: cada objetivo atómico p(t1 , t2 , ..., tn ) puede verse como un proceso, cuyo estado del programa es el predicado p con aridad n (p/n), y su estados de datos es la secuencias de términos t1 , t2 , ..., tn . El objetivo complejo (conjunción de objetivos atómicos) se ve como una red de procesos, cuya interconexión es especificada por variables lógicas compartidas entre los objetivos atómicos. Los procesos se comunican instanciando las variables lógicas compartidas, y sincronizan esperando que una variable lógica sea instanciada. El comportamiento de un proceso como se ha descrito se ajusta a las Cláusulas de Horn con Guardas como se muestra a continuación: H ← G1 , ..., Gn : B1 , ..., Bm n, m > 0 La cabeza H y la guarda G1 , ..., Gn (por sus comprobaciones) especifican las condiciones bajo las cuales puede utilizarse la cláusula para reducir un determinado objetivo. El cuerpo B1 , ..., Bm determina el estado del proceso después de haberse realizado la reducción. De este modo, dependiendo del cuerpo de la cláusula utilizada para reducir un objetivo atómico, el estado del correspondiente proceso puede cambiar su naturaleza. Si el cuerpo de la cláusula es vacío, el proceso en cuestión termina; si es unitario, formado por un solo átomo, el proceso cambia de estado; y si el cuerpo está compuesto por una conjunción de objetivos, el proceso inicial se transforma en una serie de procesos concurrentes. Un objetivo tiene la forma: ← M1 , ..., Mk k>0 Los Mi son evaluados en paralelo (paralelismo AND), utilizando las cláusulas del programa para su reducción. Para cada Mi se examinan en forma paralela las cláusulas que lo pueden reducir (paralelismo OR), seleccionándose a lo más una y sin bactracking. El criterio de selección es que el Mi unifique con la cabeza de la cláusula y se satisfagan la conjunción de guardas G1 , ..., Gn (evaluadas también en paralelismo AND), si existen. Si más de una cláusula es candidata, entonces se hace una elección no determinista entre ellas. En cada paso de reducción un objetivo Mi puede: 9.1. PROGRAMACIÓN LÓGICA Y PLC 109 Reducirse al conjunto de subobjetivos del cuerpo de la cláusula seleccionada y continuar la evaluación paralela de los subobjetivos. Reducirse utilizando una cláusula sin cuerpo (hecho) y finalizar con éxito. No unificar con la cabeza de alguna cláusula y finalizar con fracaso. Suspender, si no tiene suficientemente instanciado alguno de sus argumentos definidos con restricción de entrada. Cada argumento de un predicado tiene una definición de modo. Una declaración de modo input para un argumento de predicado, puede obligar a que ese argumento este instanciado en el momento de intentar la reducción, esto se denomina restricción de entrada para el argumento. Si en un subobjetivo todos los argumentos con restricción de entrada no están instanciados, el subobjetivo suspende, con posibilidad de deadlock si todos los subobjetivos suspenden. Es decir, la unificación entre un objetivo y la cabeza de una cláusula no es bidireccional como sucede en Programación Lógica, el programador debe especificar el uso que hará del predicado (en PARLOG esto se hace explícitamente, en KL1 el sistema lo determina). 9.1. Programación Lógica y PLC La semántica declarativa de un programa lógico concurrente (PARLOG o KL1) no es diferente a la de un programa lógico (PROLOG) dado que esta semántica es universal para todos los programas lógicos y no depende de la elección de un lenguaje de programación lógica en particular. Respecto de la semántica operacional, las diferencias más importantes son: Estrategia en la selección de objetivo: La estrategia para selección de un objetivo en PROLOG es evaluar los subobjetivos de una conjunción secuencialmente desde izquierda a derecha. Solamente un proceso de evaluación de un subobjetivo está activo a la vez. Se utiliza el mecanismo de backtracking para reintentar con subobjetivos que han fallado. Una conjunción en PARLOG o KL1 puede también ser evaluada secuencialmente de izquierda a derecha, pero lo más común es que los subobjetivos sean evaluados concurrentemente (paralelismo AND). Así, cada subobjetivo es un proceso. Muchos procesos pueden estar activos a la vez, por tanto es necesaria una sincronización, ésta es especificada por medio de la declaración de modo. No hay backtracking, cuando un subobjetivo en una conjunción fracasa, la conjunción completa fracasa. 110 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE Estrategia de elección de cláusulas: En la búsqueda de una cláusula para resolver un subobjetivo, PROLOG explora las cláusulas en forma secuencial, buscando según orden textual en el programa. En PARLOG o KL1 las cláusulas son examinadas concurrentemente (paralelismo OR). Completo: PARLOG y KL1 son incompletos como lenguajes de programación lógica porque pueden existir soluciones de acuerdo a la semántica declarativa que no son producidas como resultado de la evaluación. Una causa del por qué no son completos es la declaración de modo en los argumentos de un predicado. Por otra parte, PROLOG también es incompleto porque el lenguaje tiene una estrategia de búsqueda secuencial y en profundidad, pudiéndose presentar una evaluación que entre en un bucle infinito, sin obtenerse una respuesta. El rol de la unificación: Cuando PROLOG busca una cláusula para resolver un subobjetivo se intenta unificación completa entre todos los pares de argumentos correspondientes entre el subobjetivo y la cabeza de la cláusula. En PARLOG o KL1 cada predicado tiene asociado un modo que distingue entre argumentos de entrada y de salida, los cuales son tratados de manera diferente. A continuación se muestran implementaciones del predicado append ilustrando las diferencias indicadas antes. PROLOG append([],L,L). append([H|L1],L2,[H|L3]) :append(L1,L2,L3). PARLOG mode append(?,?,^). append([],L,L). append([H|L1],L2,[H|L3]) <append(L1,L2,L3). 9.2. COMUNICACIÓN ENTRE PROCESOS 111 Aplicando los siguiente objetivos, en cada caso se obtiene: Objetivo append([1,2],[3,4,5],[1,2,3,4,5]) append([1,2],[3,4,5],X) append([1,2],L,[1,2,3,4,5]) append(L,[3,4,5],[1,2,3,4,5]) append(L1,L2,[1,2,3,4,5]). PROLOG yes X=[1,2,3,4,5] ; L=[3,4,5] ; L=[1,2] ; L1 = [] L2 = [1,2,3,4,5] ; L1 = [1] L2 = [2,3,4,5] ; L1 = [1,2] L2 = [3,4,5] ; L1 = [1,2,3] L2 = [4,5] ; L1 = [1,2,3,4] L2 = [5] ; L1 = [1,2,3,4,5] L2 = [] ; PARLOG yes X=[1,2,3,4,5] L=[3,4,5] [deadlock] [deadlock] Los últimos dos objetivos provocan un deadlock en PARLOG pues los argumentos con restricción de entrada no están suficientemente instanciados para permitir seleccionar una cláusula, luego el objetivo suspende, y por ser el único objetivo a resolver, el sistema se bloquea. En PARLOG, el paralelismo AND puede evitarse utilizando “&” en lugar de “,” para separar los subobjetivos y los átomos del cuerpo de una cláusula. Así, la selección de subobjetivo a evaluar se hace secuencialmente (de izquierda a derecha) entre átomos separados por “&”.El paralelismo OR puede evitarse utilizando “;” en lugar de “.” para separar las cláusulas. La búsqueda de cláusula candidata se hace secuencialmente (en orden textual de arriba abajo) entre cláusulas separadas por “;”. 9.2. Comunicación entre procesos En Programación Lógica Concurrente cada objetivo en ejecución es un proceso, es decir, tiene su propio hilo de ejecución. Los procesos concurrentes se comunican al instanciar variables lógicas compartidas y se sincronizan al esperar que dichas variables sean instanciadas. Las variables lógicas son utilizadas como canales de comunicación instanciando la variable a una lista cuya cabeza y cuerpo son variables lógicas; la cabeza puede ser usada para enviar el mensaje actual y el cuerpo puede ser usado para los mensajes siguientes. Estas ideas se ilustran a continuación, implementando algunos protocolos de comunicación que usan definiciones para un productor y un consumidor. 112 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE Caso A: Comunicación unidireccional asíncrona (Figura 9.1). p naranja naranja c c p naranja c Figura 9.1: Se produce una naranja, se consume una. Programa mode p(^). p(Out) <Out = naranja. mode c(?). c(naranja) <write(’crouch!’). Ejecución | ?- p(X),c(X). crouch! X = naranja La implementación de broadcasting es inmediata, como se muestra en el siguiente objetivo. | ?- p(X),c(X),c(X). crouch!crouch! X = naranja 9.2. COMUNICACIÓN ENTRE PROCESOS 113 Caso B: Comunicación unidireccional asíncrona(Figura 9.2). 1 p 2 p ... naranja naranja ... c c ... Figura 9.2: Se produce un número ilimitado de naranjas. Programa mode p(^). p([Out|RestoOut]) <Out = naranja, p(RestoOut). mode c(?). c([naranja|RestoIn]) <write(’crouch!’), c(RestoIn). Ejecución | ?- p(X),c(X). crouch!crouch!crouch!... 114 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE Caso B’: Unidireccional asíncrona (Figura 9.3). 1 p 2 p naranja c c ... ... p N naranja naranja ... c Figura 9.3: Se producen N naranjas. Programa mode p(?,?,^). p(F,F,[]); p(I,F,[Out|RestoOut]) <Out = naranja, NewI is I + 1, p(NewI,F,RestoOut). mode c(?). c([]). c([naranja|RestoIn]) <write(’crouch!’), c(RestoIn). Ejecución | ?- p(0,3,X),c(X). crouch!crouch!crouch! X = [naranja,naranja,naranja] Nótese que el ritmo de producción del productor no tiene por qué ser igual para el consumidor. 9.2. COMUNICACIÓN ENTRE PROCESOS 115 Caso C: Bidireccional síncrona (Figura 9.4). dame_una 1 p 2 p naranja c dame_una ... naranja ... c ... Figura 9.4: El consumidor solicita ilimitadas naranjas, cada vez que se recibe una se pide otra. Programa mode p(?,^). p([dame_una|RestoIn],[Out|RestoOut]) <Out = naranja, p(RestoIn,RestoOut). 116 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE mode c(?,^). c([naranja|RestoIn],[Out|RestoOut]) <write(’crouch!’), Out = dame_una, c(RestoIn,RestoOut). Ejecución | ?- p([dame_una|X],Y),c(Y,X). crouch!crouch!crouch! ... Caso C’: Bidireccional síncrona (Figura 9.5). dame_una 1 p 2 p naranja c dame_una naranja c ... ... ... dame_una N p naranja c Figura 9.5: El consumidor solicita N naranjas. Programa mode p(?,^). p([],[]). p([dame_una|RestoIn],[Out|RestoOut]) <Out = naranja, p(RestoIn,RestoOut). mode c(?,?,?,^). c(I,F,[naranja|RestoIn],[]) <F is I + 1: write(’crouch!’); 9.2. COMUNICACIÓN ENTRE PROCESOS 117 c(I,F,[naranja|RestoIn],[Out|RestoOut]) <write(’crouch!’), Out = dame_una, NewI is I + 1, c(NewI,F,RestoIn,RestoOut). Ejecución | ?- p([dame_una|X],Y),c(0,3,Y,X). crouch!crouch!crouch! X = [dame_una,dame_una] Y = [naranja,naranja,naranja] Caso D: Bidireccional sincronizada por espera de instanciación de término incluido en mensaje incompleto (Figura 9.6). 1 p 2 p ... naranja(Ok) Ok=ok naranja(Ok) Ok=ok ... c c ... Figura 9.6: Espera usando mensaje incompleto. Programa mode p(^). p([Out|RestoOut]) <Out = naranja(OK) & data(OK) & p(RestoOut). mode c(?). c([naranja(OK)|RestoIn]) <write(’crouch!’), OK = ok, c(RestoIn). 118 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE Ejecución | ?- p(X),c(X). crouch!crouch!crouch! ... Caso E : Comunicación N:1. Si N es un número determinado antes de la ejecución, bastaría con tener un merge que combine N entradas. Por ejemplo, la Figura 9.7 ilustra el caso N=2. p naranja naranja merge p c naranja Figura 9.7: Más de un productor enviando mensajes a un mismo consumidor. Utilizando alguna de las definiciones para p y c de los casos anteriores junto a un merge típico, la comunicación 2:1 se conseguiría con el siguiente objetivo : <- p(X1),p(X2),merge(X1,X2,X),c(X). Sin embargo, si N no se conoce de antemano la solución anterior no es aplicable pues el merge que se defina siempre tiene un número fijo de entradas. Una fácil solución en PARLOG es utilizar el merge implícito en las sentencias de manipulación de canales: create_channel, write_channel y close_channel. Con estas sentencias se crea, escribe y cierra un merge implícito con un número no determinado de entradas, este merge es llamado canal y tiene un identificador establecido en la creación, con el cual es referenciado en la escritura y cierre. 9.3. OBJETOS Y CLASES EN PLC 119 p naranja p naranja ... naranja c p Figura 9.8: Utilizando un merge sin límite de entradas. canal_y_consumidor <create_channel(entrada,X), c(X). mode c(?). c([naranja|RestoIn]) <write(’crouch!’), c(RestoIn). p <write_channel(entrada,naranja), p. Así, en este caso el predicado canal_y_consumidor crea un canal llamado entrada el cual es una variable compartida con el argumento de c. El predicado p escribe en el canal. Si se tienen varias ocurrencias del objetivo p todas escribirán al mismo canal, el sistema realiza el merge implícito. La Figura 9.8 ilustra esta situación. En este caso el objetivo, dependiendo del N deseado, sería : <- canal_y_consumidor,p,...,p. 9.3. Objetos y clases en PLC Primero se mostrará en términos generales cómo algunos conceptos de programación orientada a objeto pueden ser reflejados en un programa lógico concurrente, las ideas fundamentales fueron establecidas en [46]. Como ya se mencionó, se utilizará el enfoque en el cual los objetos son como procesos perpetuos, los cuales se comunican enviando mensajes. En Programación Lógica Concurrente dicha enfoque se traduce en las siguientes funcionalidades claves: 120 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE Cada predicado tiene asociada un conjunto de cláusulas contra las cuales puede efectuar su reducción, esto constituye la plantilla de objeto. Cada cláusula de la plantilla tiene recursividad de cola, es decir, en el cuerpo de la cláusula el predicado de la cabeza se vuelve a lanzar como objetivo (a esto se debe el nombre de objetos perpetuos). La excepción es el caso de finalización de la sesión del sistema, para la cual cada objeto tiene asociada una cláusula sin recursividad de cola. Cada objeto es un objetivo en reducción. El estado del objeto está representado por el valor de los términos usados como argumentos del objetivo. En cada reducción del objetivo dichos valores podrían cambiar. Para determinar el valor de un atributo de un objeto puede utilizarse tanto una perspectiva deductiva como una dinámica (temporal). En el enfoque deductivo se tiene un argumento para registrar la traza de acciones y para cada atributo se establece un predicado que deduce el valor del atributo a partir de la traza actual del objeto. En el enfoque dinámico se tiene uno o varios argumentos que registran sólo el valor actual de los atributos. Se ha experimentado con ambos enfoques. En el apéndice A se incluyen dos ejemplos utilizando el enfoque deductivo. Finalmente se optó por el enfoque dinámico por ser el utilizado en OASIS 2.2. La comunicación, interpretada como envío de mensajes, es provista mediante la instanciación parcial de variables compartidas entre los objetivos en reducción. Un objeto cliente se comunica con el objeto servidor escribiendo el mensaje en una variable compartida entre ambos. La instanciación parcial se consigue implementando la variable compartida como una lista, lo cual simula un canal de envío/recepción de mensajes. Cada clase es también un objetivo que mediante su reducción, en el cuerpo de las cláusulas que definen el predicado de la clase, cumplirá esencialmente dos tareas : • Atenderá el mensaje de creación de instancias de la clase. Para ello existirá una cláusula que además de proveer recursividad en cola para el objetivo que representa a la clase, generará un nuevo objetivo representando a la instancia creada. • Distribuir los mensajes desde un cliente a una instancia particular de la clase, efectuando la relación entre el identificador usado para referenciar al objeto y el oid del objeto, y luego escribiendo el mensaje en el canal de la instancia correspondiente. Para cumplir esta tarea, el objetivo que representa a la clase contendrá un término que almacena la población de la clase (una lista de términos que 9.3. OBJETOS Y CLASES EN PLC 121 relaciona identificador de objeto con canal de recepción de mensajes del objeto). El siguiente programa ilustra las ideas expuestas. En el programa se tienen tres predicados clase/2, objeto/2 y enviar_a_todos/3, los dos primeros constituyen la plantilla para instancias (objetivos) clase y objeto, el último es un predicado usado en una cláusula del predicado clase/2 para implementar un broadcasting del mensaje stop a cada instancia de la clase. mode clase(?,?). clase([new|Resto],[OidSiguiente,Poblacion]) <concat_atom([oid,OidSiguiente],Oid) & create_channel(Oid,In) & NOidSiguiente is OidSiguiente+1 & objeto(In,[Oid,0,verde]), clase(Resto,[NOidSiguiente,[Oid|Poblacion]])). clase([fin|Resto],[OidSiguiente,Poblacion]) <enviar_a_todos(stop,Poblacion) & close_channel(c). mode enviar_a_todos(?,?). enviar_a_todos(Evento,[]). enviar_a_todos(Evento,[Oid|Resto]) <write_channel(Oid,Evento), enviar_a_todos(Evento,Resto). 122 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE mode objeto(?,?). objeto([e1|RestServicios],[Oid,N,C]) <not(C==verde): objeto(RestServicios,[Oid,N,C]); objeto([e1|RestServicios],[Oid,N,C]) <NN is N+1 & CC = rojo & objeto(RestServicios,[Oid,NN,CC]). objeto([e2|RestServicios],[Oid,N,C]) <not(N > 0): objeto(RestServicios,[Oid,N,C]); objeto([e2|RestServicios],[Oid,N,C]) <NN is N-1 & CC = verde & objeto(RestServicios,[Oid,NN,CC]). objeto([e3|RestServicios],[Oid,N,C]) <NN is N+1 & CC = rojo & objeto(RestServicios,[Oid,NN,CC]). objeto([stop|RestServicios],[Oid,N,C]) <close_channel(Oid). Los predicados clase/2 y objeto/2 utilizan su primer argumento como una variable compartida que será instanciada parcialmente implementando así un canal de comunicación. El segundo argumento de clase u objeto representa a variables de estado, para clase son : OidSiguiente y Poblacion, para objeto son : Oid, N y C. Para cada cabeza de cláusula se establecen instanciaciones apropiadas para la variable compartida, con lo cual se consigue dirigir la reducción del objetivo hacia la cláusula que reflejará la admisión del mensaje y que en su cuerpo contiene el comportamiento asociado a dicha admisión de mensaje. En nuestro ejemplo un objeto clase reconoce los mensajes new y fin, un objeto objeto reconoce los mensajes e1, e2 y e3. En las guardas se ponen condiciones adicionales a la recepción de un cierto mensaje. Sólo una cláusula podrá ser seleccionada. El usuario del programa lanzará el siguiente objetivo para ejecutar el sistema: && create_channel(c,X),clase(X,[1,[]]). 9.3. OBJETOS Y CLASES EN PLC 123 El objetivo create_chanel(c,X) crea un canal (variable compartida) identificada por c, esto implementa un merge implícito de todos los mensajes que se escriban en dicho canal. El objetivo clase(X,[1,[]]) crea el objeto que representa a la clase, asociándole en su canal de entrada la variable del canal identificado por c, además sus atributos tienen los siguiente valores: OidSiguiente=1, Poblacion=[]. Los “&&” permiten lanzar el objetivo en segundo plano para evitar que se produzca deadlock y poder introducir objetivos adicionales. En este momento de la sesión sólo se tiene el objetivo clase en espera por instanciación de su canal de entrada. A continuación se podría lanzar el siguiente objetivo write_channel(c,new). Este objetivo tiene éxito y escribe en el canal c el mensaje new, el objetivo clase([new|X’],[1,[]]) podrá ahora reducirse utilizando la cláusula correspondiente, con lo que se generará el primer objeto(In,[oid1,0,verde]). El objetivo en este estado de la computación será: <- clase(Resto,[2,[oid1|Poblacion]]), objeto(In,[oid1,0,verde]). 0 fin 1 new Figura 9.9: Diagrama de transición de estados para el proceso clase. 124 CAPÍTULO 9. PROGRAMACIÓN LÓGICA CONCURRENTE 0 new e2 1 fin e1 e2 e3 2 fin e3 Figura 9.10: Diagrama de transición de estados para el proceso objeto. Es decir, tenemos en ejecución el objeto que representa a la clase y una instancia de dicha clase. Posteriormente podemos comunicarnos con la clase para continuar creando instancias mediante el mensaje new o comunicarnos con cualquiera de las instancias creadas lanzando los mensajes e1, e2 o e3 al canal identificado por su Oid. Las Figuras 9.9 y 9.10 muestran las secuencias de mensajes que pueden recibir los objetos modelados en el ejemplo. 9.4. Conclusiones del capítulo Se ha hecho una breve introducción a la Programación Lógica Concurrente. Particularmente se han analizado los tipos de comunicación entre procesos ofrecidos. Un objeto en Programación Lógica Concurrente puede ser representado en forma natural y directa como un proceso perpetuo, es decir, un objetivo que se reduce y cambia de estado repetidamente. El predicado usado para reducir dicho objetivo corresponde a la plantilla de clase, en la cual diferentes cláusula permiten modelar distintos comportamientos para cada servicio. La comunicación entre objetos se establece mediante variables compartidas entre los objetivos correspondientes. Así, mediante instanciación parcial de dichas variables compartidas se consigue el efecto de envío de un mensaje desde un objeto a otro. Utilizando el paralelismo AND cada objetivo (objeto) tiene su propio hilo de ejecución. Capítulo 10 PLC y OASIS En este capítulo se estudia la representación de conceptos OASIS en Programación Lógica Concurrente (PLC). Así, dada una especificación en OASIS se podrá establecer un conjunto de pautas de traducción que permitan generar automáticamente el programa lógico concurrente correspondiente a una especificación OASIS. La Programación Lógica Concurrente es un paradigma de programación con características apropiadas para la animación de especificaciones de sistemas dentro del enfoque orientado a objeto, ofreciendo un grado de implementación suficiente para prototipación dentro de un marco con posibilidades de justificación formal. La integración de la Programación Lógica Concurrente y la Programación Orientada a Objeto ha motivado varias enfoques y propuestas. Esta Tesis se enmarca dentro de las propuestas que modelan los objetos como procesos perpetuos, enfoque inspirado en los trabajos de Shapiro y Takeuchi [84]. Algunas propuestas en esta línea son: Polka [18] y L2||O2 [74] basados en PARLOG y A’UM [100] basado en GHC [95]. Sin embargo, la motivación en este trabajo de Tesis es diferente, no se pretende aumentar la expresividad del lenguaje lógico concurrente sino que proporcionar ejecutabilidad a una especificación OASIS mediante traducción automática hacia un lenguaje lógico concurrente. Se ha escogido Programación Lógica Concurrente como entorno de programación por las siguientes razones: Los conceptos de orientación a objeto de OASIS tienen una directa representación en Programación Lógica Concurrente. Esto se constató en [46]. La concurrencia en Programación Lógica Concurrente permite que cada objeto tenga su propio hilo de ejecución. 125 126 CAPÍTULO 10. PLC Y OASIS Es posible proveer una semántica declarativa y operacional para OASIS desde la perspectiva de la Programación Lógica Concurrente según las equivalencias establecidas. Existen varias propuestas que abordan la definición formal de la semántica para lenguajes lógicos concurrentes, entre ellas [7, 8, 6]. Esto permitiría a su vez justificar (al menos en parte) la equivalencia del programa lógico concurrente obtenido por traducción automática respecto de la especificación OASIS asociada. Además, PARLOG y KL1, los lenguajes lógicos concurrentes que se han utilizado, son de libre uso. Los primeros experimentos relacionando conceptos OASIS con Programación Lógica Concurrente se hicieron con PARLOG [46]. Fruto de esto se determinaron las correspondencias básicas presentadas anteriormente. PARLOG y KL1 son muy similares en cuanto a funcionalidad. Sin embargo, desde el punto de vista de la prototipación de especificaciones OASIS, son relevantes las siguientes comparaciones: Todos los elementos de la especificación OASIS relacionados con verificación de condiciones (precondiciones, condiciones de evaluación, condiciones de derivación, condiciones de disparo, condiciones de restricciones de integridad, etc.) se corresponden directamente con el concepto de guardas de cláusulas en Programación Lógica Concurrente. Por esto, resulta bastante más abreviado el programa obtenido si el lenguaje permite la especificación de guardas profundas1 , de lo contrario, para verificar condiciones deben crearse cláusulas intermedias adicionales. PARLOG provee cláusulas profundas, KL1 no. Respecto a la implementación de comunicación inter-objeto, esto en PARLOG es mucho más sencillo de implementar por disponer de primitivas para creación, escritura y cierre de canales, estas realizan implícitamente el merge que establece la comunicación muchos-a-uno necesaria para cada objeto en su papel de servidor. En KL1 dicha mezcla debe hacerse explícitamente manipulando variables denominadas vectores. En cuanto a plataforma sobre la cual se pueden ejecutar, PARLOG se restringe a máquinas Sun. KLIC el compilador de KL1, se puede instalar en cualquier plataforma UNIX. Además, los programas PARLOG requieren arrancar su ambiente para ser ejecutados. Los programas KL1, son traducidos por KLIC a C, es decir, se genera un código ejecutable 1 Se dice que un lenguaje lógico concurrente permite “guardas profundas” si es posible usar en una guarda predicados adicionales a los provistos por el sistema. Cuando no se permiten guardas profundas el lenguaje (o su versión) se califica como “plana” (flat ). 10.1. REPRESENTANDO UNA ESPECIFICACIÓN OASIS EN KL1 127 independiente. Esto último facilita la integración del programa generado con otros programas. El grupo de investigación que daba soporte para PARLOG se disolvió a principios de los 90’s y no se tiene conocimiento de esfuerzos de continuación. Por otra parte, KL1 fue una pieza fundamental en la investigación llevada a cabo por el ICOT (Institute for New Generation Computer Technology) mediante el proyecto FGCS (Fifth Generation Computer Systems). Aunque el proyecto finalizó, el AITEC (Research Institute for Advanced Information Technology), sucesor del ICOT, se ha hecho cargo hasta la actualidad de la difusión y continuo desarrollo del lenguaje. Aunque las dos primeras comparaciones favorecen a PARLOG, las dos últimas resultaron más relevantes y determinantes para decidir utilizar KL1 como lenguaje a ser generado. Por lo cual todos los trabajos posteriores asociados a esta tesis se basaron en KL1. 10.1. Representando una especificación OASIS en KL1 En este apartado se estudiará en detalle cómo una especificación OASIS puede ser representada mediante un programa KL1. Los detalles de algunas cláusulas serán omitidos para facilitar su lectura. 10.1.1. Clases y objetos En Programación Lógica Concurrente una sociedad de objetos puede ser vista (en tiempo de ejecución) como un objetivo a resolver, donde cada objeto es un subobjetivo. Cada subobjetivo es evaluado usando paralelismo AND (concurrencia inter-objeto). El siguiente objetivo representa la situación descrita. ← object1 (In1 , Out1 , State1 ), ..., objectk (Ink , Outk , Statek ) k>0 Ini es el canal de entrada para las acciones que el objeto podría proveer. A su vez, Ini es usado como oid para el objeto. Outi es canal de salida para las acciones requeridas por el objeto. Statei es una lista de términos de la forma att(Attribute, value), uno para cada atributo del objeto. En general, en tiempo de ejecución se requiere creación (y destrucción) de objetos. Por esto, deben existir subobjetivos con la capacidad de generar (en su reducción) una nueva instancia. Estos subobjetivos corresponden en 128 CAPÍTULO 10. PLC Y OASIS forma natural a la noción de clase como factoría de objetos. Así, las clases son también implementadas como subobjetivos del objetivo que inicia la ejecución. Una clase tiene un atributo llamado P opulation, el cual es una lista de pares (Ini , Key) para cada instancia de la clase. Ini es el Oid del objeto, Key es una lista de atributos constantes que permiten referenciar al objeto. El nombre del predicado para una clase es el mismo nombre de la clase. Para un objeto el nombre del predicado será el nombre de la clase precedido por “o_”. o_account o_account o_customer o_customer o_account (Oid2) (Oid4) (Oid3) (Oid1) customer (Oid5) account Figura 10.1: Una situación de ejecución para el ejemplo bancario. Ejemplo 33 Un situación de ejecución para el ejemplo bancario. En la Figura se ilustra una situación de ejecución en la cual existen dos instancias de customer y tres instancias de account. El objetivo asociado (omitiendo algunos detalles) sería el siguiente: :- ...,customer(...),o_customer(Oid1,...),o_customer(Oid2,...), account(...),o_customer(Oid3,...),o_customer(Oid4,...), o_customer(Oid1,...). El programa lógico concurrente que representa una especificación OASIS estará compuesto por: Para cada clase especificada, un conjunto de cláusulas cuyo predicado en la cabeza lleva el nombre de la clase. Para cada clase especificada, un conjunto de cláusulas cuyo predicado en la cabeza lleva el nombre o_clase. Un conjunto de cláusulas para los predicados de librería. 10.1.2. Comunicación entre objetos El mecanismo de comunicación ofrecido por la Programación Lógica Concurrente es la variable compartida entre subobjetivos, interpretada como un canal de comunicación entre subobjetivos. Para permitir que muchos objetos se 10.1. REPRESENTANDO UNA ESPECIFICACIÓN OASIS EN KL1 129 Router action(Clientx,Servery,Event) Object Clientx action(Clientx,Servery ,Event) Server Class action(Clientx ,Servery,Event) Object Servery Figura 10.2: Esquema de comunicación entre objetos comuniquen con un determinado objeto se ha implementado la configuración mostrada en la Figura 10.2. En general, si un objeto cliente clientx tiene que establecer una comunicación con un objeto servidor servery (que puede ser el mismo objeto cliente), clientx instanciará parcialmente la variable que representa a su canal de salida Out. La variable Out es mezclada con el resto de variables de salida de los objetos y proporcionada como canal de entrada para un objetivo adicional llamado router. El router tiene tantos canales de salida como clases hay en el sistema. Cada vez que el router recibe una acción en su entrada pondrá la acción en el canal de salida asociado a la clase del objeto servidor de la acción. El objetivo original al ejecutar un programa KL1 es el átomo main. Así, en el cuerpo de este predicado se establece el esquema de comunicación descrito. Ejemplo 34 La cláusula asociada al predicado main definida para el ejemplo del sistema bancario. main:take_active_actions(ExternActions), UserActions=[action(c(tester),s(user),e(add,[att(userid,root)])) |InUser], user(InUser,OutUser,[att(population,[])]), customer(InCustomer,OutCustomer,[att(population,[])]), account(InAccount,OutAccount,[att(population,[])]), generic:new(merge,{ExternActions,OutUser,OutCustomer,OutAccount}, Actions), router(Actions,InUser,InCustomer,InAccount). 130 CAPÍTULO 10. PLC Y OASIS El predicado take_active_actions coge las acciones externas durante la sesión de animación. Siempre existirá una clase llamada user y una instancia de dicha clase cuyo atributo userid tiene el valor root. Esto permite que el analista durante la animación y en representación del objeto root introduzca acciones que no tiene un cliente especificado, en nuestro ejemplo esto sucede con las acciones de creación de objetos customer u objetos account. Del mismo modo, el analista podrá introducir acciones en representación de cualquier objeto que pueda actuar como cliente. 10.1.3. Comportamiento del objeto Cada objeto intenta reducirse a sí mismo usando las cláusulas que representan su especificación. Cada cláusula que reconoce una acción es capaz de reducir al objeto a un conjunto de subobjetivos. A continuación se muestra el subobjetivo o_classi (In∗ , Out∗ , State∗ ) que representa a un objeto y la forma de las cláusulas que pueden utilizarse para reducirlo. In∗ , Out∗ y State∗ representan las variables lógicas In, Out y State en un determinado momento de la resolución. Se consideran p, q, s, t > 0 y r > 0. : −..., o_classi (In∗ , Out∗ , State∗ ), ... o_classi ([actioni1 |In], Out, State) : − Gi1 , ..., Gip | Bi1 , ..., Bit , o_classi (In, NOut, NState). ... o_classi ([actionir |In], Out, State) : − Gi1 , ..., Giq | Bi1 , ..., Bis , o_classi (In, NOut, NState). 10.1.4. Creación y destrucción de objetos Las clases son subobjetivos lanzados en el objetivo inicial. Las nuevas instancias se obtienen por reducción del subobjetivo asociado a una clase cada vez que se recibe una acción con el evento new. La creación de un objeto implica que los siguientes subobjetivos son generados: ... NOut = {Out, ObjectOut}, o_class(Oid, ObjectOut, Attributes), 10.1. REPRESENTANDO UNA ESPECIFICACIÓN OASIS EN KL1 131 ... Out es el canal de acciones requeridas por el subobjetivo asociado a la clase. Este canal es separado en dos nuevas variables lógicas. NOut será usada como nuevo canal de salida para la clase. ObjectOut será el canal de acciones requeridas para el nuevo objeto. Oid es una variable lógica que será usada como Oid del nuevo objeto y a la vez representa el canal de acciones a proveer. Ejemplo 35 La cláusula que reduce al subobjetivo asociado a la clase account cuando acontece una acción de creación (acción cuyo servicio solicitado es el evento open2 ). En el cuerpo de la cláusula puede verse el lanzamiento del nuevo subobjetivo asociado a la instancia creada de la clase account. account([action(Client,s(account),e(open,Attributes))|RestActions], Out,State) :Out={NOut,ObjectOut}, o_account(Oid,ObjectOut,Attributes), get_attributes(Attributes,[att(number,Number)]), NPopulation=[object(Oid,Number)|Population], update_state(State,[chg(population,NPopulation)],NState), ... account(RestActions,NOut,NState). get_attributes es un predicado que extrae algunos valores de atributo desde una lista. El predicado update_state modifica una lista de atributos produciendo una nueva lista con ciertos cambios indicados en su segundo argumento. Cuando la acción solicitando open(101,john,0,0,1234,0,false) es recibida, el subobjetivo account es: account(action(Client,c(account), e(open,[101,john,0,0,1234,0,false]))|Rest],Out,State) Utilizando la cláusula antes mostrada, el subobjetivo es reducido finalmente a dos subobjetivos, uno correspondiente al relanzamiento de la clase y otro asociado al nuevo objeto, tal como se muestra a continuación: ... o_account(Oid,ObjectOut,[att(number,101),att(name,john), att(balance,0),att(times,0),att(pin,1234), att(rank,0),att(good_balance,false)]), account(Rest,NOut,[att(population,[object(Oid,101)]]). La destrucción de un objeto es obtenida mediante una reducción del respectivo subobjetivo pero utilizando una cláusula cuyo cuerpo no relanza a 2 Un evento de creación tiene implícitamente como argumentos todos los atributos constantes y variables del objeto que se creará. 132 CAPÍTULO 10. PLC Y OASIS dicho objeto. Es decir, se trata de una cláusula sin recursividad de cola, así, la ejecución del objeto finaliza. 10.1.5. Cambio de estado Los objetos son implementados como procesos perpetuos (al menos mientras no son destruidos) porque entre los subobjetivos en los cuales un objeto es reducido vuelve a aparecer el objeto. Esto produce el efecto de continuidad en la vida del objeto. Cada vez que el objeto es relanzado alguno de sus atributos pueden ser diferentes respecto del subobjetivo anterior. De esta forma se refleja el cambio de estado debido a la ocurrencia de una acción. El efecto “ejecutar una acción” es obtenido en la reducción cuando el nuevo canal de acciones a proveer es el del subobjetivo anterior con excepción de la acción recién ejecutada. Las fórmulas que definen el estado alcanzado inmediatamente después de la ocurrencia de la acción corresponden a subobjetivos que asignan nuevos valores a los atributos del objeto. Ejemplo 36 La ejecución de la acción asociada al evento deposit(10) enviado al objeto creado anteriormente es representada como una reducción del siguiente subobjetivo: o_account([action(Client,s(account,id(number,[att(number,101)])), e(deposit,[10]))|RestIn],Out,[att(number,101),att(name,john), att(balance,0),att(times,0),att(pin,1234),att(rank,0), att(good_balance,false)]) Este subobjetivo es reducido usando la siguiente cláusula: o_account([action(Client,Server,e(deposit,[N]))|Rest],Out,State) :get_attributes(State,[att(balance,Balance),att(times,Times)]), NBalance:= Balance+N, NTimes:= Times+1, LExp1:= NBalance, RExp1:= 100, test_condition([[c(ge,LExp1,RExp1)]],NGood_balance), update_state(State,[chg(balance,NBalance),chg(times,NTimes), chg(good_balance,NGood_balance)],NState) o_account(Rest,Out,NState). El predicado test_condition evalúa una lista de conjunciones representando una Fbf de la especificación. Si todos las conjunciones son satisfechas el segundo argumento de test_condition es instanciado a true, de lo contrario su valor será false. Finalmente, el objetivo es reducido a uno nuevo con 10.1. REPRESENTANDO UNA ESPECIFICACIÓN OASIS EN KL1 133 un nuevo estado (NState), es decir, el objeto ha cambiado de estado. En el ejemplo el objetivo resultante es: o_account(Rest,Out,[att(number,101),att(name,john),att(balance,10), att(times,1),att(pin,1234),att(rank,0),att(good_balance,false)]) 10.1.6. Permisos y prohibiciones Las prohibiciones para acciones son implementadas mediante predicados intermedios invocados desde el cuerpo de las cláusulas de un objeto. Ejemplo 37 A continuación se muestra la cláusula que verifica las precondiciones de la solicitud de servicio withdraw(1234,10). check_one_o_account_condition(action(Client,This,e(withdraw,[P,N])), State,Result,Msg) :utility:get_attributes(State,[att(balance,Balance), att(rank,Rank),att(pin,Pin)]), LExp1:= Balance, RExp1:= N, LExp2:= Balance, RExp2:= N, LExp3:= Rank, RExp3:= 2, LExp4:= P, RExp4:= Pin, test_condition([[c(eq,LExp4,RExp4),c(ge,LExp1,RExp1)], [c(eq,LExp4,RExp4),c(lt,LExp2,RExp2),c(eq,LExp3,RExp3)]], Result), Msg=not([[c(eq,LExp4,RExp4),c(ge,LExp1,RExp1)], [c(eq,LExp4,RExp4),c(lt,LExp2,RExp2),c(eq,LExp3,RExp3)]]). Esta vez el predicado test_condition es utilizado para instanciar a true o false la variable Result, la cual representa si la Fbf del permiso se satisface. Cuando la precondición no se satisface se genera una acción requerida al cliente original y que incluye el mensaje Msg, el cual indica la Fbf no satisfecha. 10.1.7. Obligaciones En OASIS la comunicación entre objetos es activada por obligaciones. Este trabajo se centra en el mecanismo fundamental de comunicación representado por los disparos en OASIS. Los disparos representan comunicación asíncrona y son implementados ejecutando Out = [Action|NOut] sin esperar una respuesta. Los disparos se generan debido a la satisfacción de una Fbf en el estado actual del objeto. Así, en el cuerpo de cada cláusula que implementa un cambio de estado relacionado con la Fbf asociada se añade un objetivo que evalúa la condición y realiza el disparo. Esta sentencia aparecerá en el cuerpo de una 134 CAPÍTULO 10. PLC Y OASIS cláusula seleccionada en la reducción de un objeto cliente. Out es el identificador de la variable compartida que constituye el canal de acciones requeridas por el objeto. NOut es la nueva variable para el canal de acciones requeridas. Las acciones deben primero llegar al router, el cual envía la acción al correspondiente canal de entrada de la clase servidora. Si el servidor de la acción es una instancia de la clase, dicha clase buscará en su atributo P opulation la variable que representa al canal de entrada del objeto servidor. Ejemplo 38 Un objetivo representando a un objeto de la clase account al alcanzar un nuevo estado: o_account([action(this,self,e(pay_commission,[]))|In],Out, [att(number,101),att(name,john),att(balance,80), att(times,5),att(pin,1234),att(rank,0),att(good_balance,false)]) La posibilidad de activación de un disparo en el nuevo estado fue detectada durante el calculo del cambio de estado. La cláusula encargada de este trabajo fue: verify_o_account_triggers([t1|RestTriggers],State,Triggers) :utility:get_attributes(State,[att(times,Times), att(good_balance,Good_balance),att(rank,Rank)]), LExp1:= Times, RExp1:= 5, LExp2=Good_balance, RExp2=false, LExp3:= Rank, RExp3:= 0, utility:test_condition([[c(ge,LExp1,RExp1), c(eq,LExp2,RExp2),c(eq,LExp3,RExp3)]],Answer), utility:get_attributes(State,[att(number,Number)]), utility:put_trigger(Answer, action(this,self,e(pay_commission,[])), Triggers,NTriggers), verify_o_account_triggers(RestTriggers,State,NTriggers). El predicado put_trigger pone la acción a disparar en la lista de disparos (NTriggers) si la variable Answer es instanciada a true. En este ejemplo el predicado test_condition instanciaría a true la variable Answer con lo cual en el buzón Mbox, inmediatamente siguiente, el objeto tendrá como acción obligada de ejecutar la siguiente: action(this,self,e(pay_commission,[])) Esta acción debe ser disparada y se reconoce porque el cliente es el término this. Así, dicha acción es puesta en el canal de salida usando: 10.2. CONCLUSIONES DEL CAPÍTULO 135 Out=[action(This,self,e(pay_commission,[]))|NOut] Esta vez, This está instanciada con la identificación del objeto, como cliente de la acción generada. 10.2. Conclusiones del capítulo Las representación de clases y objetos presentada en el capítulo anterior fue refinada en términos de conceptos específicos de OASIS. Para cada concepto OASIS se estableció una correspondiente representación en KL1. De esta forma una especificación de clase en OASIS puede ser traducida a un programa lógico concurrente. A partir de este trabajo se determinaron plantillas de traducción OASIS-KL1 mediante las cuales se construyó un programa traductor que genera automáticamente un programa KL1 a partir de una especificación OASIS almacenada en un repositorio. En el apéndice C se presenta parte de las plantillas establecidas y ejemplos de código KL1 generado automáticamente. 136 CAPÍTULO 10. PLC Y OASIS Capítulo 11 LUNA: Una herramienta basada en OASIS En este capítulo se elabora una propuesta global para la animación automática de especificaciones OASIS. LUNA es un ambiente de software para la especificación incremental y validación de modelos conceptuales OASIS. LUNA está parcialmente terminado en su primera versión. El núcleo del entorno lo constituye un programa traductor que a partir de una especificación OASIS genera un programa lógico concurrente que sirve como prototipo para validar la especificación. El capítulo está organizado de la siguiente forma: primero se provee una descripción introductoria del entorno, posteriormente se detallan cada uno de sus módulos y finalmente se presenta un proceso de construcción incremental y validación de requisitos apoyado por el entorno de animación propuesto. 11.1. Ambiente de especificación incremental y validación En el contexto de OASIS el comportamiento del sistema corresponde al comportamiento de la sociedad de objetos incluidos en él y puede ser observado a través de las acciones acontecidas y los estados alcanzados por cada objeto. La animación de una especificación OASIS debe permitir examinar el comportamiento de un objetos o grupo de objetos, explorando las acciones acontecidas (generadas internamente o desde el exterior al grupo de objetos observados) y los correspondientes estados alcanzados. Esta facilidad exploratoria ya constituye una mejora para la validación del modelo conceptual. Sin embargo, para una validación dirigida a contrastar requisitos y que a la vez aproveche en mayor medida la animación se propone: especificar los requisitos funcionales del sistema usando escenarios en términos de objetos involucrados, 137 138 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS acciones acontecidas y estados alcanzados. De esta forma, se consigue una representación de los requisitos que es comparable con la observación a realizar en la animación del modelo conceptual. comportamiento esperado escenarios elementos de especificación modificación y/o extensión de escenarios Asistente para construir escenarios Entorno gráfico de especificación Repositorio basado en el modelo de OASIS Entorno gráfico de animación comparación animación versus comportamiento esperado Prototipo Traductor resultados comparación Figura 11.1: Ambiente para especificación y validación de especificaciones OASIS La Figura 11.1 muestra cómo las ideas planteadas se materializan en un entorno software para la especificación incremental y validación de modelos conceptuales. Los componentes del entorno (en el rectángulo de la derecha) son: un asistente para especificar escenarios en el formato adecuado para su comparación, un subentorno gráfico de especificación que editar el modelo conceptual, un repositorio que almacena el modelo conceptual y los escenarios, un traductor que genera automáticamente un prototipo a partir del modelo conceptual almacenado y un subentorno de animación para interactuar de manera exploratoria con el prototipo o para validar específicamente cada uno de los escenarios almacenados respecto del comportamiento del prototipo. En términos generales, se trata de un trabajo que puede ser extendido (o integrado) en el desarrollo de una herramienta CASE. Sin embargo, se ha prescindido de características no estrictamente relacionadas con la construcción incremental y validación del modelo conceptual. La programación de las interfaces gráficas se ha realizado con Tcl/Tk [68]. Los componentes del entorno (en el rectángulo de la derecha en la Figura 11.1) son: Un asistente para construir escenarios. La programación de este módulo aún no se ha comenzado. Las técnicas usadas para especificar escenar- 11.2. REPOSITORIO OASIS 139 ios varían considerablemente (ver [80]) desde textuales a gráficas, desde informales a formales, etc. Con respecto del entorno propuesto, el objetivo es poder realizar una comparación de resultados obtenidos por animación respecto de resultados esperados incluidos en los escenarios. De esta forma, interesa que tanto la especificación de escenarios caracterice el comportamiento esperado mediante trazas de acciones y estados alcanzados de la vida de los objetos estudiados, tal como se obtienen de la animación del modelo conceptual. Un entorno gráfico de especificación, que permite editar el modelo conceptual. Este módulo permite la edición gráfica del modelo, definiendo los elementos de la especificación que se almacenan en el repositorio. Para las especificaciones de proceso de una clase (operaciones y protocolos) se ha integrando un editor gráfico de diagramas de transición de estados. El repositorio, que almacena el modelo conceptual y los escenarios. Corresponde a un metamodelo estático para especificaciones OASIS sobre un modelo relacional. Un traductor de OASIS a Programación Lógica Concurrente que genera automáticamente un prototipo a partir del modelo conceptual almacenado. El entorno de animación, que permite al analista interactuar adecuadamente con el prototipo. La idea es ofrecer tanto una validación exploratoria como una validación dirigida a comprobar cada uno de los escenarios establecidos respecto del comportamiento del prototipo. 11.2. Repositorio OASIS Considerando el propósito de este trabajo, el repositorio OASIS surge con la necesidad de disponer de una estructura de almacenamiento para especificaciones OASIS a partir de la cual pueda generarse automáticamente un prototipo en KL1. Una vez establecidas las pautas de traducción (plantillas) OASIS-KL1, incluyendo todas las correspondencias estudiadas, el paso siguiente para implementar la automatización requería como entrada una estructura de almacenamiento para especificaciones OASIS. Así, el repositorio haría el papel de pivote entre la especificación y la prototipación. Una posibilidad era establecer una estructura de almacenamiento en memoria primaria y además definir un fichero de intercambio en un determinado formato, esto último para posibilitar la conexión entre distintas herramientas. Sin embargo, para permitir una mejor integración entre herramientas se decidió establecer 140 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS una estructura en almacenamiento secundario para ser implementada en un gestor de base de datos. Además, de acuerdo a la tecnología imperante, el objetivo fue diseñar una base de datos relacional. Desde la perspectiva de modelado, el repositorio debería ser el metamodelo estático de una especificación OASIS, es decir, una especificación OASIS de la estructura de cualquier especificación OASIS concreta. Sin embargo, considerando que el objetivo sólo era definir un modelo relacional, se optó por un enfoque más pragmático orientado a definir un modelo sintáctico para especificaciones OASIS, basado en la BNF del lenguaje. La primera versión de una BNF para OASIS 2.2 (extendido con todos los aspectos necesarios para animación automática) y el correspondiente repositorio relacional fue establecido en [47]. En su primera versión el repositorio era poblado directamente a partir de una especificación OASIS textual utilizando un analizador sintáctico. En 16 proyectos de fin de carrera posteriores se trabajó utilizando dicho repositorio, lo cual sirvió para depurarlo. Finalmente, con la aparición de OASIS 3.0 (el cual incluyó todas las extensiones que habían sido consideradas sobre la versión anterior) y dentro del marco del proyecto MENHIR [63], el repositorio fue actualizado para la sintaxis de la nueva versión [77]. 11.3. Entorno gráfico de especificación La Figura 11.2 muestra la versión actual de este módulo que permite especificar gráficamente el Diagrama de Configuración de Clases [72] y en forma textual los detalles de la plantilla de una clase. Este módulo sirve de entrada a todo el entorno de animación propuesto. En él es posible modificar o crear un repositorio, modificando o creando esquemas conceptuales dentro de ellos. Una vez establecidos el repositorio y el esquema conceptual de trabajo, el analista puede modificar el diagrama de configuración de clases. Haciendo clic en alguna de las clases es posible acceder a la especificación de la misma, tal como se ilustra en la Figura 11.2. De esta forma se pueden especificar: identificadores, atributos, eventos, evaluaciones, precondiciones, disparos, protocolos y operaciones. Además en la parte inferior de dicha ventana pueden detallarse las características particulares de cada relación en la cual participa la clase especificada. En particular, para la especificación de protocolos y operaciones se utiliza un subentorno de edición de Diagramas de Transición de Estados [72]. La Figura 11.4 muestra la representación gráfica de un protocolo en la versión actual de dicho subentorno. Toda la información introducida acerca de la especificación, sea gráfica o textual, es almacenada en el repositorio OASIS de la herramienta. Desde la 11.4. TRADUCTOR OASIS-PLC 141 Figura 11.2: Entorno Gráfico de Especificación. ventana de la Figura puede realizarse una verificación de consistencia de la especificación (seleccionando entre las opciones del menú “Especificación”) y generar la especificación OASIS textual correspondiente al modelo introducido. Una vez que la especificación ha sido verificada con éxito, puede generarse automáticamente un prototipo para animación. Nótese que la especificación debe satisfacer unas restricciones mínimas de completitud y consistencia para posibilitar su prototipación. Mediante la opción de menú “Simulación” se accede al subentorno de animación. 11.4. Traductor OASIS-PLC Se ha construido un programa traductor que accede al repositorio OASIS y genera una serie de ficheros KL1, éstos son traducidos a C (usando el compilador KLIC) y finalmente el código C resultante es compilado para obtener el prototipo de la especificación. El programa traductor de OASIS a KL1 está escrito en lenguaje C. La Figura 11.5 muestra un esquema simplificado de la generación de código KL1 desde el repositorio. Tal como se aprecia en dicha 142 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Figura 11.3: Especificación de una clase. figura en el total del código generado es posible identificar tres aspectos (que en el código resultante se mezclan): el código asociado estrictamente a los requisitos modelados en la especificación (que puede variar significativamente de un sistema a otro), el código asociado al modelo de ejecución (integrado dentro del anterior pero con una estructura no cambiante) y finalmente el código de librería que es igual para todos los sistemas (por esto, como veremos dicho código no se genera sino que se integra al traducir de KL1 a C). 11.4. TRADUCTOR OASIS-PLC 143 Figura 11.4: Subentorno para edición de Diagramas de Transición de Estados. Código por Modelo de ejecución Traducción automática Modelo OASIS Código por Requisitos Prototipo para animación Código de librería Figura 11.5: Tres aspectos en el código KL1 de un prototipo. 144 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS 11.4.1. Alcance del prototipo generado El entorno de especificación y el repositorio usados actualmente permiten cubrir prácticamente toda la expresividad de OASIS 2.2 incluyendo además muchas de las mejoras de OASIS 3.0. Sin embargo, y por limitaciones de alcance del presente trabajo, en cuanto a generación de prototipo, actualmente se ha abordado sólo una parte de dicha expresividad. Se ha intentado equilibrar el avance logrado en cuanto a repositorio, entorno de especificación y modelo de ejecución. Los aspectos de una especificación OASIS que hasta la fecha se pueden animar automáticamente son: Clases simples. Atributos (constantes, variables y derivados). Identificadores de objetos (identificadores alternativos y posiblemente formados por más de un atributo). Eventos Evaluaciones (incluyendo perspectiva cliente) Precondiciones Disparos Protocolos y Operaciones (sin incluir anidamiento, comunicación del tipo call/return ni action waiting). Aunque otras importantes características aun no están incorporadas, es posible efectuar validación de requerimientos para especificaciones de clases considerando al menos un comportamiento restringido de ellas. Entre los aspectos no tratados y que deberán ser incorporados en futuras versiones se puede destacar: Relaciones entre clases Comunicación action waiting, action calling y action sharing. Restricciones de Integridad Transacciones 11.4. TRADUCTOR OASIS-PLC 11.4.2. 145 Plantillas para generación de código KL1 Con las correspondencias entre OASIS y Programación Lógica Concurrente (en particular las establecidas con KL1), descritas en el capítulo anterior, se determinaron plantillas1 de traducción [49] para cada uno de los elementos del programa que deben ser generados. Estas plantillas incorporan el modelo de ejecución común a todas las especificaciones OASIS. El proceso de generación de un prototipo consiste en completar dichas plantillas con la información del repositorio para un sistema en particular. El enfoque seguido es similar al utilizado en OBLOG [67] y System Architect [76], en los cuales se provee un lenguaje de scripts el cual incorpora primitivas de acceso al repositorio. De esta forma se facilita la tarea de generación a distintos lenguajes y/o en distinto estilo para un mismo lenguaje. Sin embargo, los scripts no son fácilmente legibles. En este trabajo no se consideró interesante trabajar con un lenguaje de scripts puesto que el lenguaje de generación era sólo uno y el estilo también. Por otra parte, la necesidad de realizar continuos experimentos modificando las plantillas hacía imprescindible que éstas fueran legibles. Finalmente, cuando se alcanza una generación satisfactoria las plantillas se mantienen sin cambios. La desventaja de utilizar plantillas y no un lenguaje de scripts es que las plantillas deben ser implementadas en un lenguaje de programación para construir el traductor (en este trabajo se ha utilizado C), con lo cual las modificaciones de una plantilla deben posteriormente (y en forma manual) trasladarse al código del traductor. La información desde el repositorio se obtiene de forma directa recorriendo las tablas mediante sus relaciones. Por ejemplo, para obtener los atributos de un objeto de una clase se consulta la tabla atributos usando el campo nro_clase, de manera que éste corresponda a la clase que se está generando. Un aspecto que no es tan directo, es la representación y tratamiento de acciones. En una especificación OASIS los clientes y servidores de las acciones muchas veces son implícitos, pero en la ejecución deben ser tratados explícitamente. Se han considerado las siguientes representaciones particulares para clientes y servidores: Cliente puede ser uno de los siguientes términos self, this o c(clase). El término this es el cliente implícito para todas las acciones que representan una obligación del objeto. Si el cliente es una clase se utiliza el nombre de la clase como término cliente. Si el cliente no es declarado en la especificación OASIS, se usa la variable Client lo cual implica que el cliente puede ser cualquiera. 1 Se ha preferido utilizar simplemente la palabra “plantilla” en lugar de otras usadas en el ámbito de generación automática de código, tales como: framework, arquitectura, etc. Esta últimas más elegantes pero a la vez menos precisas. 146 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Servidor puede ser self, this, s(society,everyone), s(clase,everyone) o s(clase). Servicio es el término e(evento_u_operación,Args), donde evento_u_operación es un nombre de evento u operación en la signatura de la clase especificada y Args es una lista de los valores de argumentos en el mismo orden en el cual fueron puestos en la declaración del evento u operación. Las correspondencias entre clientes especificados en OASIS y términos en PLC se muestra en la siguiente tabla: Cliente en OASIS no declarado self “::”(obligación) society(someone) clase clase(someone) clase(Id,Value) Cliente en PLC Client self this c(society,someone) c(clase) c(clase,someone) c(clase,id(Id,Value)) Del mismo modo, las correspondencias entre servidores especificados en OASIS y términos en PLC se muestra en la siguiente tabla: Servidor en OASIS self society(everyone) clase clase(everyone) clase(Id,Value) Servidor en PLC self s(society,everyone) s(clase) s(clase,everyone) s(clase,id(Id,Value)) Estructura del prototipo El código KL1 del prototipo para un esquema conceptual está formado por los siguientes predicados (generados en el fichero prototipo.kl1): Los predicados main y router para arrancar la sesión de prototipación y establecer los enlaces de comunicación entre objetos. Un par de predicados c_clase y o_clase por cada clase del sistema. Estos predicados definen los proceso perpetuo correspondientes a la clase y a sus instancias. El tratamiento para ambos casos es homogéneo. El evento declarado new para instancias de clase es un evento del objeto que representa a la clase, el evento destroy es un evento de cada instancia. Los procesos al reducirse por recepción de acciones en su canal 11.4. TRADUCTOR OASIS-PLC 147 de entrada enviarán toda la información relevante hacia la interfaz del entorno de animación (o la registrarán en el fichero test.res cuando se haga la animación con entrada por lotes). En todo sistema existe una clase llamada user que recibe las acciones introducidas por el analista (o lee desde el fichero del caso de prueba, llamado test.dat) y encamina las acciones hacia el router. Los predicados de librería, predicados comunes invocados en los cuerpos de las cláusulas de los otros predicados. Una vez generado el ficheros con el código fuente KL1 se invoca al compilador KLIC de la siguiente forma: klic prototipo.kl1 Esto produce directamente un programa ejecutable, pasando automáticamente por una etapa intermedia de traducción a código C. Con las plantillas establecidas en [49] se construyó un programa en C (aproximadamente 5.000 líneas código fuente) que genera cada grupo de cláusulas del fichero prototipo.kl1. La traducción, generación del prototipo y su ejecución se realizan en una máquina UNIX. La Figura 11.6 muestra los pasos, las líneas de código y tamaños asociados a la generación del prototipo para el ejemplo del sistema bancario (con las clases cliente y cuenta). Aunque el tamaño del prototipo resultante es considerable (1.4 Mb), no aumenta considerablemente cuando se tienen más clases, esto se debe a la generación automática a C que realiza el compilador KLIC, paso en el cual se añade gran cantidad de código por defecto. Traductor automático Modelo OASIS 2 clases 60 líneas 1 Kb Traductor Klic Programa KL1 2.100 líneas 75 Kb Compilador C Programa en C > 17.000 líneas 0.5 Mb Programa ejecutable 1.4 Mb Figura 11.6: Un ejemplo de los pasos de generación automática Desde el punto de vista del programa KL1 gererado por el traductor OASIS-KL1, se tienen las siguientes estadísticas: 148 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Predicados main y router de librería por cada clase Nro. Predicados 2 41 16 Nro. Cláusulas 3 + (4*Nro. clases2 ) 129 32 + (3*Nro. servicios) + (1*Nro. disparos) Así, en ejemplo bancario simplificado se tienen los siguientes datos: Predicados main y router de librería por clases Nro. Predicados 2 41 48 91 Nro. Cláusulas 15 129 127 406 Figura 11.7: Primera versión del Entorno de Animación 2 Contabilizando la clase user. 11.5. ENTORNO DE ANIMACIÓN 11.5. 149 Entorno de animación Hasta el momento se han desarrollado tres versiones para este entorno. En la primera versión [49] las sesiones de prototipación se hacían mediante procesamiento por lotes. Un fichero servía de entrada para en prototipo y contenía una secuencia de acciones a ser aplicadas. Las clases e instancias ejecutaban dichas acciones y registraban su comportamiento y estado en un fichero de salida. Posteriormente el analista examinaba dicho fichero de salida y lo comparaba manualmente con el comportamiento esperado. En el Apéndice D se detalla una sesión de animación utilizando esta versión. Este enfoque resulta útil cuando se tienen que aplicar muchas acciones (por el analista) al prototipo y ellas están bien definidas previamente. Sin embargo, cuando se quiere realizar una validación exploratoria o debe existir una interacción más compleja con el analista, este enfoque no resulta apropiado. Sin embargo, las posibilidades ofrecidas debían mantenerse en futuras versiones porque cuando se contara con el asistente para construir escenarios sería imprescindible hacer animaciones en modo de entrada por lotes (batch) y así, poder realizar comparaciones en forma automática. Esto ha hecho que en las posteriores versiones el módulo de animación se centre en establecer una interfaz más adecuada para la validación exploratoria sin que esto haya producido cambios en la forma en la cual el prototipo es generado. La Figura 11.7 muestra la interfaz de la segunda versión del entorno de animación, que puede ser ejecutada en una página Web mediante la instalación del Plug-In para Tcl/Tk. La funcionalidad es similar a la ofrecida por la tercera versión. Sin embargo, se desecho la idea de continuar trabajando con el Plug-In (es decir, con el animador incrustado en una página Web) puesto que los comandos inhabilitados restringen demasiado la interacción posible de incorporar. A continuación se describe la tercera versión para el entorno de animación. La Figura 11.8 ilustra el inicio de la sesión de animación. La animación empieza desde el ambiente integrado, donde previamente se carga (o se crea) un esquema conceptual, se verifica su consistencia y se genera el prototipo. La ventana de la Figura 11.8 está dividida en dos áreas: a la izquierda el área de objetos permite visualizar los objetos que están activos y a la derecha se muestran las listas de acciones procesadas hasta el último tick significativo (aquel en el cual algún objeto alcanzó un nuevo estado). Se ha implementado un mecanismo versátil de filtros para la visualización de acciones y facilitar el análisis de las trazas de objetos. Por un lado, en el área de objetos se puede seleccionar un objeto, un grupo de objetos o todos los objetos del esquema conceptual (haciendo clic en el fondo del área izquierda). Adicionalmente, con los botones del área derecha, se puede seleccionar el subconjunto de acciones que se desea visualizar. Por defecto se muestran todas (Mboxi ), 150 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Figura 11.8: Inicio de la sesión de animación pero se pueden filtrar las obligadas de requerir (OReqi ), las no-obligadas de ejecutar (OExeci ), las acciones en conflicto (Confi ), las acciones ejecutadas (Execi ) o las acciones rechazadas (Rejecti )3 . Los botones de la parte inferior del área izquierda tienen la siguiente funcionalidad: el botón play comienza la animación; el botón stop detiene la animación para comenzar una nueva con play; el botón pausa suspende la animación y habilita los botones rewind y forward que permiten retroceder o avanzar examinando las trazas en ticks ya ejecutados (el área de la derecha se refresca a medida que se cambia el tick. Al avanzar o retroceder sólo se muestran los ticks significativos. Al comienzo, se refleja la creación de un metaobjeto por cada clase del esquema. Además, también por defecto, se crea un objeto user identificado por root. A través de este objeto el analista puede crear las instancias necesarias de las clases correspondientes. Al hacer un click sobre un objeto aparece la ventana de la Figura 11.9. Esta ventana muestra todas las clases y servicios que son accesibles para el objeto seleccionado. Además, se mostrará una ventana indicando el estado del objeto seleccionado. Por defecto, el objeto user(root) puede acceder a todos las clases del esquema y a todos sus servicios. Para otros objetos dicho acceso depende exclusivamente de las interfaces establecidas en el esquema conceptual. En la ventana de la Figura 11.9 se realiza la creación de dos instancias de cuenta (con número 101 y 102) y una instancia de cliente identificado por el nombre “diego”. Después de lanzar las acciones de creación y hacer clic en el fondo del área 3 En esta versión del traductor y entorno de animación no ha sido incorporado el tratamiento de acciones obligadas de proveer (OP rovi ). 11.6. PROCESO DE ESPECIFICACIÓN Y VALIDACIÓN 151 Figura 11.9: Construcción de acciones de creación de instancias de objetos, la ventana resultante se muestra en la Figura 11.10. A continuación, se recreará un escenario en el cual un objeto cliente realiza cuatro depósitos y un reintegro en una cuenta. Los servicios solicitados son: deposit(10), deposit(20), deposit(30), deposit(40) y withdraw(50). Seleccionando el objeto customer(diego) se accederá a una ventana similar a la Figura 11.9 desde la cual el analista puede construir las acciones y requerir los servicios en representación del objeto customer(diego). Las cinco acciones serán enviadas al objeto account(101). Si posteriormente se selecciona el objeto account(101) y se presiona el botón Execi , puede verse en la Figura 11.11 la lista de todas las acciones ejecutadas hasta el último tick significativo. La Figura 11.12 muestra el estado del objeto account(101) a partir de dicho tick. 11.6. Proceso de especificación y validación El proceso de construcción del modelo conceptual, en términos generales contendría las siguientes actividades: 1. Capturar requisitos del usuario mediante técnicas de escenarios. 2. Especificar los escenarios en una forma representativa para su comparación (objetos, acciones y estados alcanzados). 3. Especificar los elementos de la especificación asociados a cada escenario y que determinan partes del modelo conceptual. 4. Verificación automática de la consistencia del modelo conceptual y de los escenarios introducidos. 152 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Figura 11.10: Sesión de animación después de crear tres instancias 5. Obtención automática de un prototipo para animación. 6. Validación del modelo conceptual. Mediante animación de la especificación se contrasta el funcionamiento del sistema respecto de cada escenario introducido. Además, realizando una animación exploratoria pueden buscarse situaciones de funcionamiento que evidencien comportamientos no deseados o que el modelo conceptual no está completo. 7. Modificación y/o extensión del conjunto de escenarios. Estas actividades se repetirían en la secuencia establecida hasta conseguir un resultado satisfactorio en lo que respecta a la actividad 6. Cualquier modificación en los requisitos funcionales del sistema determinaría posibles cambios en los escenarios, con lo cual se volvería a entrar en el ciclo de actividades indicadas. 11.7. Conclusiones del capítulo Se ha presentado una versión preliminar de la herramienta LUNA, un ambiente para la especificación incremental y validación de especificaciones OASIS. LUNA permite especificar gráficamente un modelo conceptual OASIS. La orientación hacia validación se ve reflejada en dos entornos específicos: un asistente para la construcción de escenarios (aún no construido) y un entorno de animación (versión preliminar). Mediante la traducción automática de una especificación OASIS en un prograrma KL1, se dispone de un prototipo el cual es utilizado para contrastar su comportamiento respecto del comportamiento 11.7. CONCLUSIONES DEL CAPÍTULO 153 Figura 11.11: Acciones ejecutadas por el objeto account(101) Figura 11.12: Estado actual del objeto account(101) esperado, este último incluido en los escenarios especificados. En el estado actual de la herramienta, se traducen especificaciones OASIS (incluyendo clases simples y abarcando casi toda la plantilla de clase) y es posible realizar una validación exploratoria interactuando con el prototipo a través del entorno de animación. El propósito final es que LUNA se integre dentro del contexto más amplio de una herramienta CASE. 154 CAPÍTULO 11. LUNA: UNA HERRAMIENTA BASADA EN OASIS Capítulo 12 Conclusiones El aporte indirecto más importante de este trabajo de Tesis lo constituyen las extensiones y mejoras sobre OASIS 2.2, formando todas ellas parte fundamental de la nueva versión: OASIS 3.0. Las principales contribuciones en este sentido son: incorporación de la perspectiva cliente, una nueva formalización para las especificaciones de proceso en el marco de la Lógica Dinámica y un esquema de comunicación más preciso y completo. Además, se ha establecido un modelo de ejecución para especificaciones OASIS 3.0. Se determinaron correspondencias entre conceptos OASIS y Programación Lógica Concurrente, mediante las cuales se definieron plantillas de traducción que fueron finalmente implementadas en un programa traductor. Se constató que la representación de clases y objetos en Programación Lógica Concurrente resulta directa. Gracias a la concurrencia ofrecida por el lenguaje (PARLOG y KL1) cada objeto (y la clase como un objeto más) se implementa como un proceso con su propio hilo de ejecución y la comunicación se establece mediante variables compartidas. De esta forma la representación es natural respecto de la semántica dada a los objetos en OASIS. Así, no se tiene que introducir un monitor para gestionar la actividad del sistema como ocurre en el caso de implementaciones usando un lenguaje secuencial. Se diseñó e implementó un repositorio para almacenar especificaciones OASIS. El traductor genera automáticamente un programa KL1 a partir de una especificación OASIS almacenada en el repositorio. Se elaboró una propuesta de ambiente para la especificación incremental y validación de modelos conceptuales OASIS basada en animación automática, describiendo el proceso asociado. El traductor OASIS-KL1 es el elemento clave de la propuesta. En este marco, se construyó una versión preliminar para el entorno gráfico de especificación que permite introducir el modelo conceptual OASIS y almacenarlo en el repositorio. También se construyó una versión preliminar para el entorno de animación que posibilita la interacción adecuada 155 156 CAPÍTULO 12. CONCLUSIONES del analista con el prototipo (programa KL1 automáticamente generado). 12.1. Trabajo futuro Respecto de la herramienta construida y su posterior mejora o extensión para incluir toda la expresividad de OASIS 3.0, existen cuatro aspectos a considerar: modelo de ejecución OASIS, repositorio OASIS, traductor OASIS-KL1 y entornos de especificación y animación. El repositorio actual incluye todas las características de OASIS 3.0. El modelo de ejecución debe ser extendido para considerar restricciones de integridad y transacciones. Estas extensiones involucran también cambios en el traductor OASIS-KL1. Se está trabajando actualmente en un aplanamiento de las relaciones entre clases de manera que con un paso intermedio (previo a la generación de código KL1) se obtiene una representación equivalente de la especificación, pero sin incluir dichas relaciones. La idea es aplanar las jerarquías de especialización estableciendo directamente las plantillas asociadas y eliminar las jerarquías de agregación reemplazándolas por determinados esquemas de comunicación entre objetos. Así, el modelo de ejecución, traductor y del entorno de animación no deben ser extendidos para incluir dichas características. El entorno “asistente gráfico para construir escenarios” no ha sido aún desarrollado. Esto es indispensable para poder conseguir algún grado de automatización en la comparación entre el comportamiento esperado y el comportamiento exhibido por el prototipo. En particular, se constató que para la validación sería interesante incorporar animación simbólica tal como se plantea en [4, 37]. La evaluación simbólica permite que los escenarios sean parcialmente especificados. Aquellos aspectos no especificados son tratados simbólicamente con todos los casos (relevantes a la especificación) y automáticamente explorados. Esto provee un medio para explorar clases de escenarios simultáneamente. También sería conveniente asistir automáticamente la validación exploratoria mediante generación automática de escenarios. Existen técnicas de prueba que ayudan a la generación de casos de pruebas. Con alguna adaptación en dichas técnicas, que utilizan pseudocódigo o código fuente, podrían ser aplicadas a especificaciones OASIS. Por ejemplo, de camino básico (para operaciones y protocolos), pruebas de condiciones, de valores límite, etc. Por otra parte, la equivalencia entre el programa lógico obtenido respecto de la especificación OASIS es una materia aún pendiente. Sin embargo, en nuestro caso la verificación y demostración de dicha equivalencia (al menos en forma parcial) se ve favorecida por tres importantes factores: primero el modelo conceptual es especificado en un lenguaje formal (OASIS), segundo el modelo abstracto de ejecución está asociado a la semántica de dicho lenguaje 12.2. PUBLICACIONES IMPULSADAS POR ESTA TESIS 157 formal y en tercer lugar existen varias propuestas que abordan la formalización de Lenguajes Lógicos Concurrentes [6, 7, 8]. Esto ofrece la posibilidad de justificar formalmente las equivalencias entre constructores del modelo conceptual OASIS y el programa obtenido para animación. Así, los factores indicados proveen un camino de formalización en el cual se puede trabajar. De todas formas, debe destacarse que la situación actual de este trabajo no es peor que la mejor situación posible en muchas otras propuestas de validación usando prototipación, más aún si se trata de enfoques basados en un proceso de generación manual e informal del prototipo. El problema planteado es en sí una de las tareas pendientes no sólo en prototipación sino en la obtención del producto final. Hasta nuestros días no existen técnicas de verificación que aseguren la equivalencia 100 % de un producto de software (considerando un producto de carácter industrial) respecto de una determinada especificación. 12.2. Publicaciones impulsadas por esta Tesis A continuación de indican las publicaciones en las cuales ha participado el autor y que han sido producto directo del desarrollo de esta Tesis. Estas han sido agrupados según los objetivos parciales perseguidos y clasificados por tipo de publicación. También se ha incluido el número de Proyectos de Fin de Carrera dirigidos por el autor en la Facultad de Informática de la UPV entre los años 1995 y 1999, los cuales han sido desarrollados en el marco de esta Tesis. El resumen de publicaciones es el siguiente: 1 libro, 1 artículo en revista, 9 artículos en congresos, 6 informes técnicos y 21 Proyectos de Fin de Carrera. Extensión de OASIS para establecer una proceso de generación automática de prototipos Libro: “OASIS 3.0: Un enfoque formal para el modelado conceptual orientado a objeto” (1998) [56]. Artículo en revista: “Representación de objetos en teorías y su traducción a un modelo de concurrencia”(1997) [82]. Artículos en congresos: “Especificaciones de proceso para objetos y su representación e Lógica Dinámica” (1998) [55], “Un modelo abstracto de ejecución para especificaciones OASIS 3.0” (1998) [52] y “Modelado conceptual con un lenguaje formal y orientado a objeto” (1999) [83]. Informes técnicos: “Modelado de la perspectiva cliente en especificaciones OASIS” (1997) [48] y “Formalización de OASIS en Lógica Dinámica incluyendo especificaciones de proceso” (1997) [53]. 158 CAPÍTULO 12. CONCLUSIONES Traducción de OASIS a Programación Lógica Concurrente Artículos en congresos: “Animation of system specifications using concurrent logic programming” (1997) [51], “Animación de modelos conceptuales para ayudar en la validación de requisitos” (1997) [50], “Animación de especificaciones OASIS en entornos concurrentes” (1998) [54], “Prototyping a Requirements Specification Through an Automatically Generated Concurrent Logic Program” (1999) [57] y “Animation of Conceptuals Models using two Concurrent Environments: An overview”(1999) [59]. Informes técnicos: “Conceptos básicos de OASIS implementados en Programación Lógica Concurrente” (1996) [46] y “Guías para la generación automática de un programa lógico concurrente que sirve de prototipo para una especificación OASIS” (1997) [49]. Proyectos de Fin de Carrera: 5. Construcción de un ambiente para validación y especificación incremental de especificaciones OASIS Artículos en congresos: “Un ambiente para especificación incremental y validación de modelos conceptuales (1999) [58]. Informes técnicos: “Un metamodelo estático para especificaciones OASIS y su implementación en una base de datos relacional (1996) [47] y “Un modelo estático para especificaciones OASIS 3.0 y su implementación en una base de datos relacional (1999) [77]. Proyectos de Fin de Carrera: 16. Apéndice A Ejemplos en PARLOG En este apéndice se presentan dos ejemplos que ilustran con mayor detalle cómo clases y objetos pueden ser implementados utilizando Programación Lógica Concurrente. Los ejemplos han sido desarrollados utilizando PARLOG. A.1. Pequeña biblioteca Se modelan tres clases: usuario, libro y lector. Para este ejemplo, sólo los objetos de la clase usuario son activos (requieren servicios), los objetos de las clases libro y lector son pasivos (sólo proveen servicios). Debido a que el número de objetos libro y lector no es fijo, las clases libro y lector son implementadas como objetos que proveen el servicio new asociado a la creación de objetos o_libro y o_lector, respectivamente. La Figura A.1 ilustra el esquema del problema. Se optó por establecer un broadcast de mensajes desde el objeto usuario hacia los objetos lector, libro, o_lector y o_libro, los servicios desconocidos para un objeto son simplemente ignorados. Los eventos de consulta se establecieron mediante mensajes incompletos. La solución utiliza el enfoque deductivo para establecer el estado de los objetos en un instante determinado. El objetivo que representa al objeto incluye como argumento la traza de eventos relevantes que acontecen. Así, para obtener el valor de cada atributo del objeto existe un predicado que procesa la traza del objeto. Los servicios implementados son los siguientes: new_libro(Key,Autor,Anno): Crea objeto o_libro. new_lector(Key,Direccion,Fono): Crea objeto o_lector. prestar(Lector,Libro): Registra un préstamo, evento compartido por objetos o_lector y o_libro. 159 160 APÉNDICE A. EJEMPLOS EN PARLOG ... devolver prestar np disponible destroy o libro new_libro libro usuario new_lector devolver prestar npc pc npv pv lector o-lector ... Figura A.1: Esquema de comunicación en la pequeña biblioteca devolver(Lector,Libro): Registra una devolución, evento compartido por objetos o_lector y o_libro. np(Key,Num): Obtiene Num, el número de préstamos del libro del objeto. disponible(Key,Resp): Obtiene Resp, valor que representa si está o no prestado el libro. destroy(Key): Destruye el objeto cuyo mecanismo de identificación tiene el valor Key. npc(Key,Num): Obtiene Num, el número de préstamos concedidos al lector. pc(Key,Prestamos): Obtiene Prestamos, una lista con los préstamos concedidos al lector. npv(Key,Num): Obtiene Num, el número de préstamos vigentes del lector. pv(Key,Prestamos): Obtiene Prestamos, una lista con los préstamos vigentes del lector. A.1. PEQUEÑA BIBLIOTECA 161 En cada servicio, Key representa el atributo utilizado para identificar al objeto. A continuación se muestra un ejemplo de ejecución del sistema pequeña biblioteca. | ?- usuario(X),libro(X),lector(X). >new_lector(juan,valencia,111). new_lector(juan,valencia,111) >npc(juan,N). npc(juan,0) >new_lector(pedro,madrid,555). new_lector(pedro,madrid,555) >new_libro(parlog,conlon,1989). new_libro(parlog,conlon,1989) >disponible(parlog,R). disponible(parlog,si) >new_libro(bd,date,1992). new_libro(bd,date,1992) >prestar(juan,parlog). prestar(juan,parlog) >prestar(juan,bd). prestar(juan,bd) >npc(juan,N). npc(juan,2) >npv(juan,N). npv(juan,2) >devolver(juan,parlog). devolver(juan,parlog) >disponible(bd,R). disponible(bd,no) >disponible(parlog,R). disponible(parlog,si) >npv(juan,N). npv(juan,1) >pc(juan,L). pc(juan,[prestar(juan,bd),prestar(juan,parlog)]) >pv(juan,L). pv(juan,[prestar(juan,bd)]) >prestar(pedro,parlog). prestar(pedro,parlog) >np(parlog,N). np(parlog,2) >stop. X = [new_lector(juan,valencia,111),npc(juan,0), new_lector(pedro,madrid,555),new_libro(parlog,conlon,1989), disponible(parlog,si),new_libro(bd,date,1992), prestar(juan,parlog),prestar(juan,bd),npc(juan,2), npv(juan,2),devolver(juan,parlog),disponible(bd,no), disponible(parlog,si),npv(juan,1),pc(juan,[prestar(juan,bd), prestar(juan,parlog)]),pv(juan,[prestar(juan,bd)]), prestar(pedro,parlog),np(parlog,2)] yes | ?- Como se observa, la animación comienza al establecer el objetivo que contiene los subobjetivos que representan a las clases del sistema. La variable compartida X implementa la comunicación entre los objetos (y clases), quienes se comunican instanciando parcialmente dicha variable. Cada vez que se ejecuta un evento de creación (new_libro o new_lector) se lanza un nuevo subobjetivo asociado al objeto creado. 162 APÉNDICE A. EJEMPLOS EN PARLOG A continuación se presenta el código PARLOG para las definiciones de las clases usuario, libro y lector, junto a sus respectivas definiciones para instancias en los predicados o_usuario, o_libro y o_lector, respectivamente. mode usuario(^). 1 usuario(Salida) <write(’> ’) & read(Mensaje), o_usuario(Mensaje,Salida). mode o_usuario(?,^). o_usuario(stop,[]); 2 o_usuario(Mensaje,[Mensaje|Salida]) <- ground(Mensaje) & write(Mensaje) & nl & write(’> ’) & read(Otro_mensaje) & o_usuario(Otro_mensaje,Salida). mode libro(?). 3 libro([new_libro(Key,Autor,Anno)|Ins]) <o_libro(Ins,[Key,Autor,Anno,[new(Key,Autor,Anno)]]), libro(Ins). libro([]); 4 libro([Desconocido|Ins]) <- libro(Ins). 5 mode o_libro(?,?). o_libro([destroy(Key)|Ins],[Key,Autor,Anno,Traza]). o_libro([disponible(Key,Resp)|Ins],[Key,Autor,Anno,Traza]) libro_disponible(Traza,Resp), o_libro(Ins,[Key,Autor,Anno,Traza]). 6 1 o_libro([np(Key,Num)|Ins],[Key,Autor,Anno,Traza]) libro_np(Traza,Num), o_libro(Ins,[Key,Autor,Anno,Traza]). <- <- El objetivo asociado a la clase usuario se reduce inmediatamente a un objetivo o_usuario. Esto representa la creación implícita de un objeto usuario. Así, sólo existirá un objeto usuario durante la animación. 2 La única tarea del objeto usuario es enviar mensajes al sistema instanciando parcialmente su argumento de salida. 3 El cuerpo de esta cláusula refleja la creación de una instancia de libro. 4 Los mensajes desconocidos son ignorados. 5 Como se observa, se tiene una cláusula para el reconocimiento y ejecución de cada servicio del objeto. En particular la ejecución del servicio de destrucción (destroy(Key)) no tiene asociado el relanzamiento del subobjetivo o_libro, con lo cual dicho proceso termina. 6 Se dice que np(Key,Num) es un mensaje incompleto pues Num es una variable no instanciada. En este caso el predicado libro_np(Traza,Num) instanciará Num realizando un procesamiento de la variable Traza. A.1. PEQUEÑA BIBLIOTECA 163 o_libro([prestar(Lector,Key)|Ins],[Key,Autor,Anno,Traza]) <o_libro(Ins,[Key,Autor,Anno,[prestar(Lector,Key)|Traza]]). o_libro([devolver(Lector,Key)|Ins],[Key,Autor,Anno,Traza]) <o_libro(Ins,[Key,Autor,Anno,[devolver(Lector,Key)|Traza]]). 7 o_libro([],[Key,Autor,Anno,Traza]); o_libro([Desconocido|Ins],[Key,Autor,Anno,Traza]) o_libro(Ins,[Key,Autor,Anno,Traza]). <- mode libro_disponible(?,^). libro_disponible([new(_,_,_)],si). libro_disponible([devolver(_,_)|Resto],si). libro_disponible([prestar(_,_)|Resto],no). mode libro_np(?,^). libro_np([new(_,_,_)],0). libro_np([prestar(_,_)|Resto],Num) Num is Num1 + 1, libro_np(Resto,Num1); <- libro_np([_|Resto],Num) <libro_np(Resto,Num). 8 mode lector(?). lector([new_lector(Key,Direccion,Fono)|Ins]) <o_lector(Ins,[Key,Direccion,Fono,[new(Key,Direccion,Fono)]]), lector(Ins). lector([]); lector([Desconocido|Ins]) lector(Ins). <- mode o_lector(?,?). o_lector([destroy(Key)|Ins],[Key,Direccion,Fono,Traza]). o_lector([npc(Key,Num)|Ins],[Key,Direccion,Fono,Traza]) lector_npc(Traza,Num), o_lector(Ins,[Key,Direccion,Fono,Traza]). <- o_lector([pc(Key,Prestamos)|Ins],[Key,Direccion,Fono,Traza]) lector_pc(Traza,Prestamos), o_lector(Ins,[Key,Direccion,Fono,Traza]). <- 7 El fin de la sesión de animación se determina al instanciar totalmente la variable compartida, en este caso, finalizando la lista asociada. 8 La implementación de la clase lector y sus instancias (o_lector) es similar a la explicada para libro y o_libro. 164 APÉNDICE A. EJEMPLOS EN PARLOG o_lector([npv(Key,Num)|Ins],[Key,Direccion,Fono,Traza]) lector_npv(Traza,Num), o_lector(Ins,[Key,Direccion,Fono,Traza]). <- o_lector([pv(Key,Prestamos)|Ins],[Key,Direccion,Fono,Traza]) lector_pv(Traza,Prestamos), o_lector(Ins,[Key,Direccion,Fono,Traza]). <- o_lector([prestar(Key,Libro)|Ins],[Key,Direccion,Fono,Traza]) <o_lector(Ins,[Key,Direccion,Fono,[prestar(Key,Libro)|Traza]]). o_lector([devolver(Key,Libro)|Ins],[Key,Direccion,Fono,Traza]) <o_lector(Ins,[Key,Direccion,Fono,[devolver(Key,Libro)|Traza]]). o_lector([],[Key,Direccion,Fono,Traza]); o_lector([Desconocido|Ins],[Key,Direccion,Fono,Traza]) o_lector(Ins,[Key,Direccion,Fono,Traza]). mode lector_npc(?,^). lector_npc([new(_,_,_)],0). lector_npc([prestar(_,_)|Resto],Num) Num is Num1 + 1, lector_npc(Resto,Num1); <- lector_npc([_|Resto],Num) <lector_npc(Resto,Num). mode lector_pc(?,^). lector_pc([new(_,_,_)],[]). lector_pc([prestar(Key,Libro)|Resto1], [prestar(Key,Libro)|Resto2]) lector_pc(Resto1,Resto2); lector_pc([_|Resto1],Resto2) <lector_pc(Resto1,Resto2). mode lector_npv(?,^). lector_npv([new(_,_,_)],0). lector_npv([devolver(_,_)|Resto],Num) Num is Num1 - 1, lector_npv(Resto,Num1). lector_npv([prestar(_,_)|Resto],Num) Num is Num1 + 1, lector_npv(Resto,Num1); lector_npv([_|Resto],Num) <lector_npv(Resto,Num). mode lector_pv(?,^). lector_pv([new(_,_,_)],[]); <- <- <- <- A.1. PEQUEÑA BIBLIOTECA lector_pv(Traza,Prestamos_vig) <lector_pc(Traza,Prestamos_con), lector_quitar_dev(Traza,Prestamos_con,Prestamos_vig). mode lector_quitar_dev(?,?,^). lector_quitar_dev([new(_,_,_)],Prestamos_con,Prestamos_con). lector_quitar_dev([devolver(Key,Libro)|Resto], Prestamos_con,Prestamos_vig) <lector_sacar_un_prestado(Key,Libro,Prestamos_con, Prestamos_sin_uno), lector_quitar_dev(Resto,Prestamos_sin_uno,Prestamos_vig); lector_quitar_dev([_|Resto],Prestamos_con,Prestamos_vig) <lector_quitar_dev(Resto,Prestamos_con,Prestamos_vig). mode lector_sacar_un_prestado(?,?,?,^). lector_sacar_un_prestado(Key,Libro,[],[]); lector_sacar_un_prestado(Key,Libro, [prestar(Key,Libro)|Resto1],Resto2) <lector_sacar_un_prestado(Key,Libro,Resto1,Resto2); lector_sacar_un_prestado(Key,Libro, [Prestamo|Resto1],[Prestamo|Resto2]) <lector_sacar_un_prestado(Key,Libro,Resto1,Resto2). 165 166 APÉNDICE A. EJEMPLOS EN PARLOG A.2. Sistema de control de nivel La Figura A.2 muestra el esquema del problema. Un controlador debe actuar abriendo o cerrando la válvula de entrada (Ve) para mantener un nivel constante de 200 cm en un depósito, el controlador recibe el nivel actual desde el sensor. La válvula de salida (Vs) tiene un comportamiento aleatorio respecto de sus aperturas y cierres. controlador Ve Qe = 6000 cm3/s sensor 200 cm Vs 200 cm Qs = 3000 cm3/s Figura A.2: Esquema del sistema de control de nivel. controlador Co2 Co1 abrir cerrar nivel Ve Ve2 abrir cerrar sensor nivel abrir cerrar Vs Vs2 Vs1 Mo4 clock T Tinicial monitor md random Figura A.3: Esquema de implementación en PARLOG para el ejemplo. La Figura A.3 muestra un esquema para la solución en PARLOG, indicán- A.2. SISTEMA DE CONTROL DE NIVEL 167 dose las clases, canales de comunicación y eventos recibidos a través de dichos canales. El sensor es simulado calculando la altura según las aperturas y cierres de las válvulas. El comportamiento aleatorio de la válvula de salida se consigue utilizando valores aleatorios generados por el objeto random. Como se verá, para todos los objetos del sistema se utiliza una perspectiva dinámica, es decir, sus estado se modela como argumentos del objetivo, que son actualizados en cada reducción. Una excepción la constituyen los objetivos o_sensor, se simula un sensor real registrando las trazas de aperturas y cierres de válvulas, calculando con ellas el nivel actual del depósito. A continuación se presenta una ejecución del sistema. Las columnas indican tiempo (en segundos desde el comienzo de la ejecución), nivel del depósito, válvula (Ve o Vs) y evento ocurrido a la válvula. El controlador actúa abriendo o cerrando la válvula de entrada para mantener el nivel entre 199 y 200 cm. | ?- control(Co1,Co2), ve(Co2,Ve2), vs(Vs1,Vs2), random(Vs1), sensor(Co1,Ve2,Vs2,Mo4), monitor(Ve2,Vs2,T,Mo4), clock(T). 35 199.0 Vs: abrir 37 198.95 Ve: abrir 65 199.65 Vs: cerrar 72 200.0 Ve: cerrar 78 200.0 Vs: abrir 99 199.475 Vs: cerrar 147 199.475 Vs: abrir 161 199.125 Vs: cerrar 166 199.125 Vs: abrir 172 198.975 Vs: cerrar 175 198.975 Ve: abrir 196 200.025 Ve: cerrar 209 200.025 Vs: abrir 250 199.0 Vs: cerrar 252 199.0 Ve: abrir 262 199.5 Vs: abrir 281 199.975 Vs: cerrar 282 200.025 Ve: cerrar 323 200.025 Vs: abrir 330 199.85 Vs: cerrar 359 199.85 Vs: abrir 389 199.1 Vs: cerrar 406 199.1 Vs: abrir 411 198.975 Ve: abrir 439 199.675 Vs: cerrar 447 200.075 Ve: cerrar 452 200.075 Vs: abrir 498 198.925 Ve: abrir 499 198.95 Vs: cerrar 508 199.4 Vs: abrir 524 199.8 Vs: cerrar 528 200.0 Ve: cerrar . . . A continuación se presenta el código PARLOG que implementa el sistema. Se especifican cláusulas para cada uno de los objetos del esquema solución. Aunque en este ejemplo no existe creación de objetos en ejecución, siguiendo el enfoque planteado en el ejemplo anterior, se han implementado las clases 168 APÉNDICE A. EJEMPLOS EN PARLOG como objetivos que en su primera reducción crean objetivos asociados a cada uno de los objetos participantes. mode control(^,^). control(Sensor,Ve) <o_control([Sensor,Ve]). mode o_control(?). o_control([Sensor,Ve]) <clock(Tactual) & 9 Sensor = [nivel(N,Tactual)|Resto1] & data(N) & 1 0 control_actuar(Ve,Resto2,N) & sleep(5000) & o_control([Resto1,Resto2]). mode control_actuar(^,?,?). control_actuar(Ve,Resto,N) <N < 199: Ve = [abrir|Resto]. control_actuar(Ve,Resto,N) <N >= 200: Ve = [cerrar|Resto]; control_actuar(Ve,Ve,N). mode monitor(?,?,?,^). monitor(Ve,Vs,Tinicial,Sensor) <o_monitor([Ve,Vs],Tinicial,Sensor). mode o_monitor(?,?,^). 1 1 o_monitor([[abrir(T)|Ve],Vs],Tinicial,Sensor) Sensor = [nivel(N,T)|Resto] & data(N) & Tiempo is T - Tinicial & write(Tiempo) & write(’ ’) & write(N) & write(’ Ve: abrir’) & nl & o_monitor([Ve,Vs],Tinicial,Resto). o_monitor([[cerrar(T)|Ve],Vs],Tinicial,Sensor) Sensor = [nivel(N,T)|Resto] & data(N) & Tiempo is T - Tinicial & write(Tiempo) & write(’ ’) & write(N) & write(’ Ve: cerrar’) & nl & o_monitor([Ve,Vs],Tinicial,Resto). o_monitor([Ve,[abrir(T)|Vs]],Tinicial,Sensor) Sensor = [nivel(N,T)|Resto] & data(N) & 9 <- <- <- El objeto control o_control consulta el nivel al objeto sensor. Para esto se utiliza un mensaje incompleto nivel(N,Tactual) donde N es una variable no instanciada. Se establece una sincronización de espera mediante el subobjetivo data(N) el cual suspende hasta que N sea instanciada. 10 Se determina si se debe abrir o cerrar la válvula de entrada (instanciando la variable Ve, compartida con el objeto válvula de entrada). Posteriormente el predicado sleep(5000) implementa una espera que consiste simplemente en ejecutar 5000 reducciones. 11 El objeto monitor o_monitor se encarga de mostrar por pantalla la actividad del sistema, indicando las aperturas y cierres de cada válvula. A.2. SISTEMA DE CONTROL DE NIVEL 169 Tiempo is T - Tinicial & write(Tiempo) & write(’ ’) & write(N) & write(’ Vs: abrir’) & nl & o_monitor([Ve,Vs],Tinicial,Resto). o_monitor([Ve,[cerrar(T)|Vs]],Tinicial,Sensor) Sensor = [nivel(N,T)|Resto] & data(N) & Tiempo is T - Tinicial & write(Tiempo) & write(’ ’) & write(N) & write(’ Vs: cerrar’) & nl & o_monitor([Ve,Vs],Tinicial,Resto). <- mode random(?). random(Vs) <o_random(Vs,13.0). mode o_random(?,?). 1 2 o_random([rnd(R,N)|Vs],Semilla) <random_gen_n(Semilla,R,N), random_gen_ns(Semilla,New_Semilla), o_random(Vs,New_Semilla). mode random_gen_n(?,?,^). random_gen_n(S,R,N) <T1 is S mod R & N is T1 + 1. mode random_gen_ns(?,^). random_gen_ns(S,NS) <T1 is 125 * S + 1 & NS is T1 mod 4096. mode sensor(?,?,?,?). sensor(Control,Ve,Vs,Monitor) <o_sensor([Control,Ve,Vs,Monitor], [199.0,[cierre(ve,0),cierre(vs,0)]]). mode o_sensor(?,?). 13 o_sensor([[nivel(N,T)|Control],Ve,Vs,Monitor],[Nivel,Traza]) sensor_tpo_ult_ap(ve,Traza,Tiempove), sensor_cambio_nivel(ve,Tiempove,T,Aumento), sensor_tpo_ult_ap(vs,Traza,Tiempovs), sensor_cambio_nivel(vs,Tiempovs,T,Disminucion), Cambio is Aumento - Disminucion, N is Nivel + Cambio, o_sensor([Control,Ve,Vs,Monitor],[Nivel,Traza]). o_sensor([Control,Ve,Vs,[nivel(N,T)|Monitor]],[Nivel,Traza]) sensor_tpo_ult_ap(ve,Traza,Tiempove), sensor_cambio_nivel(ve,Tiempove,T,Aumento), sensor_tpo_ult_ap(vs,Traza,Tiempovs), sensor_cambio_nivel(vs,Tiempovs,T,Disminucion), Cambio is Aumento - Disminucion, N is Nivel + Cambio, <- <- 12 El objeto o_random se encarga de generar números aleatorios entre 1 y 999 solicitados por la válvula de salida para determinar sus aperturas y cierres. 13 El objeto sensor o_sensor calcula el nivel del depósito de acuerdo con las aperturas y cierres de las válvulas. También informa al objeto o_control respecto del nivel del depósito. 170 APÉNDICE A. EJEMPLOS EN PARLOG o_sensor([Control,Ve,Vs,Monitor],[Nivel,Traza]). o_sensor([Control,[abrir(T)|Ve],Vs,Monitor],[Nivel,Traza]) <o_sensor([Control,Ve,Vs,Monitor],[Nivel,[apertura(ve,T)|Traza]]). o_sensor([Control,[cerrar(T)|Ve],Vs,Monitor],[Nivel,Traza]) <sensor_tpo_ult_ap(ve,Traza,Tiempo), sensor_cambio_nivel(ve,Tiempo,T,Aumento), Altura is Nivel + Aumento, o_sensor([Control,Ve,Vs,Monitor],[Altura,[cierre(ve,T)|Traza]]). o_sensor([Control,Ve,[abrir(T)|Vs],Monitor],[Nivel,Traza]) <o_sensor([Control,Ve,Vs,Monitor],[Nivel,[apertura(vs,T)|Traza]]). o_sensor([Control,Ve,[cerrar(T)|Vs],Monitor],[Nivel,Traza]) <sensor_tpo_ult_ap(vs,Traza,Tiempo), sensor_cambio_nivel(vs,Tiempo,T,Disminucion), Altura is Nivel - Disminucion, o_sensor([Control,Ve,Vs,Monitor],[Altura,[cierre(vs,T)|Traza]]). mode sensor_cambio_nivel(?,?,?,^). sensor_cambio_nivel(Valvula,0,Tactual,0); sensor_cambio_nivel(Valvula,Tiempo,Tactual,Cambio) <sensor_caudal(Valvula,Caudal), Cambio is ((Tactual - Tiempo) * Caudal) / 120000. mode sensor_tpo_ult_ap(?,?,^). sensor_tpo_ult_ap(Valvula,[apertura(Valvula,Tiempo)|Resto],Tiempo). sensor_tpo_ult_ap(Valvula,[cierre(Valvula,Tiempo)|Resto],0); sensor_tpo_ult_ap(Valvula,[_|Resto],Tiempo) <sensor_tpo_ult_ap(Valvula,Resto,Tiempo). mode sensor_caudal(?,^). sensor_caudal(ve,6000). sensor_caudal(vs,3000). mode ve(?,^). ve(Control,Sensor) <o_ve(Control,cerrada,Sensor). mode o_ve(?,?,?). 1 4 o_ve([abrir|Control],Estado,Sensor) <- Estado == cerrada: clock(Tactual) & Sensor = [abrir(Tactual)|Resto], o_ve(Control,abierta,Resto). o_ve([cerrar|Control],Estado,Sensor) <Estado == abierta: clock(Tactual) & Sensor = [cerrar(Tactual)|Resto], o_ve(Control,cerrada,Resto); 14 La válvula de entrada o_ve se abre o cierra según los mensajes que recibe desde el objeto o_control. A.2. SISTEMA DE CONTROL DE NIVEL o_ve([Accion|Control],Estado,Sensor) o_ve(Control,Estado,Sensor). 171 <- mode vs(^,^). vs(Random,Sensor) <o_vs(cerrada,[Random,Sensor]). mode o_vs(?,?). 1 5 o_vs(cerrada,[Random,Sensor]) <- Random = [rnd(1000,T1),rnd(1000,T)|Resto1] & Tiempo is T * 1000 & sleep(Tiempo) & clock(Tactual) & Sensor = [abrir(Tactual)|Resto2] & o_vs(abierta,[Resto1,Resto2]). o_vs(abierta,[Random,Sensor]) <Random = [rnd(1000,T)|Resto1] & Tiempo is T * 1000 & sleep(Tiempo) & clock(Tactual) & Sensor = [cerrar(Tactual)|Resto2] & o_vs(cerrada,[Resto1,Resto2]). mode sleep(?). sleep(N) <N =< 0 : true; sleep(N) <N1 is N - 10 & sleep(N1). 15 La válvula de salida espera un tiempo aleatorio determinado por el número entre 1 y 999 que recibe desde el objeto o_random y luego se abre o cierra dependiendo si antes estaba cerrada o abierta, respectivamente. 172 APÉNDICE A. EJEMPLOS EN PARLOG Apéndice B Repositorio OASIS El repositorio de una herramienta de modelado hace de pivote entre las diferentes actividades involucradas. Para la herramienta LUNA, el repositorio conecta la edición de la especificación con la generación automática del prototipo y su animación. Este apéndice describe el repositorio utilizado para almacenar la especificaciones OASIS 3.0. Actualmente el repositorio está implementado como una base de datos relacional que almacena especificaciones OASIS. A continuación se ilustra la estructura actual del repositorio presentando sólo su modelo conceptual (los aspectos posibles de expresar gráficamente). Para obtener mayores detalles o conocer el modelo relacional asociado consultar [77]. Se ha optado por utilizar Diagramas de Clases según la notación UML. Hay que remarcar que la lectura de los diagramas presentados debe hacerse orientada a la sintáxis del lenguaje OASIS, no en una perspectiva pura de metamodelado. Por otra parte, quizás hubiese sido más razonable presentar el modelo del repositorio usando la notación Entidad-Relación Extendida más cercana a lo que estrictamente se quería producir (una base de datos relacional), pero se decidió UML por su aceptación como notación estándar y la posibilidad de utilizar el repositorio en trabajos posteriores que incorporen el tratamiento de aspectos dinámicos. El modelo ha sido organizado en 14 paquetes interrelacionados, los cuales de muestran a continuación. 173 174 APÉNDICE B. REPOSITORIO OASIS clase nombre : string 1 cliente_servidor (from cliente-servidor) 0 ..* clave_especial : string 1 ..* 0..* 1..* {or} interfaz 0..* 1 atributos_todos : char servicios_todos : char 1 ..* 1 1 esquema_conceptual 0..* 1 1 accion (from accion) 0..* relacion (from relacion) Figura B.1: Paquete “esquema” disparo (from disparo) pr eco ndi ci on proceso 0..* (from precondicion) restriccion (from protocolo) n om bre : st ri ng (from restriccion) 0..* 1 1 0..* 0..* clase evaluacion 1 (from clase,interfaz y e_conceptual) (from evaluacion) 1 0..* nom bre : string ev_new 1 {or} ev_destroy 1 derivacion (f ro m d eri va cion) 1 0..* 1 1 0 ..* 1 0..* id ent ifi cad or (from at ributo e i de ntificador) nom bre : string card_m in : char card_m ax : char evento 0..1 0..* atributo 0 ..1 (from servicio, evento, operacion y transaccion) 1 servicio (from servicio, evento, operacion y transaccion) (from atributo e identificador) nom bre : string nom bre : string valor_defecto : string Figura B.2: Paquete “clase” 175 in ter faz (from clase,int erf az y e_conceptual) atr ibutos _todos : char ser vici os_todos : char 0..1 0..1 0..* 0..* atr ibuto ofertado ser vicio ofertado 1 0..* 1 cl iente ser vici o servi dor (f rom client e_servidor) (f rom cliente_servidor) 0..* atr ibuto (f rom servicio, event o, operacion y t ransaccion) nom bre : str ing (f rom atributo e ident ificador) nom bre : string car d_mi n : char car d_max : char valo r_defecto : str i ng Figura B.3: Paquete “interfaz” c la s e ( fr om c las e,i nter faz y e_c onc eptual) n o m b re : s t rin g 1 1 0 ..* d o m i n io 1 1 t ip o a t rib u t o 0..* 0..* a t rib u t o n o m b r e : s t rin g c a rd _ m in : c h a r c a rd _ m a x : c h a r v a lo r_ d e f e c t o : s t rin g 0 ..* id e n t if ic a d o r n o m b re : s t rin g re p re s e n t a c io n ra n g o in f e rio r : s t rin g ra n g o s u p e rio r : s t r in g {o r d e n a d a } c a rd _ m a x > 1 1 1 ..* 0..* a t r ib u t o m u lt iv a lu a d o a t rib u t o d e riv a d o a t rib u t o v a ria b le a t rib u t o c o n s t a n t e re p re s e n t a c io n : s t rin g ra n g o _ in f e rio r : c h a r ra n g o _ s u p e rio r : c h a r v a lo r_ d e f e c t o : lis t a (s t rin g ) lis t a _ c a d e n a : lis t a (s t rin g ) Figura B.4: Paquete “atributo e identificador” 0 ..* 176 APÉNDICE B. REPOSITORIO OASIS c la se (from clase,interfaz y e_conceptual) nom bre : s t ring arg um en to 1 {ordenado} 0..* se rv ic io 1 0. .* nom bre : s tring dom inio tipo (from argum ento) nom bre : s tr ing nro_ ord en : nat 0..* (from atributo e identificador) 1 0..1 1 proc es o (from protocolo) nom bre : s tring 0..* ev ento alias _f or op era cion 1 0..1 1 0.. * trans ac c ion param etro_alias _f or ev ento_c all_s hare 0.. * ev ento new ev ento des troy 1 c all_s hare 1.. * 0 . .* 1 0..* param etro_c all_s hare 1 ev ento _c all e v e nto_s hare s erv idor (fr om cliente _servi dor) Figura B.5: Paquete “servicio, proceso y parámetro” clase (fr om cl ase,i nter faz y e_ nom bre : st ring 1 0 . .* ev a lu ac ion 1 1 0. .1 c ondic io n ev alu ac ion 0 . .1 1 a c c ion 1 a sig nac ion e v aluac ion ( from accion) Figura B.6: Paquete “evaluaciones” 177 clas e ( from clase,inter faz y e_c onceptual) n om b re : s tring 1 0. . * de riv acio n 1 1 1 0. . 1 co nd ic ion deriv a ci on asig nacion deriv a cion Figura B.7: Paquete “derivaciones” clase (fr om c lase,i nter faz y e_conceptual ) nom bre : stri ng 1 0..* pr econdicion 1 1 con dicion pr econdi ci on 0..* 1 accion ( fr om acci on) Figura B.8: Paquete “precondiciones” 178 APÉNDICE B. REPOSITORIO OASIS c las e ( fr om cl ase,interfaz y e_conceptual) nom b re : s t ring 1 0. . * dis pa ro 1 0. . * 1 1 a c c ion c o ndic ion dis paro ( from accion) Figura B.9: Paquete “disparos” clase (fro m clase,interfaz y e_conceptual) nom bre : str ing 1 0..* a rgum ento {ordenado} (from argum ento) nom bre : string nro_orden : nat estado proceso nom bre : string nom bre : string 0..* 1..* 1 0..1 1 0..1 estado fuente estado destino 0..* 0..* transicion r elacion de m igracion (from P : Herencia) 1 0..1 1 guarda 0..* param etro operacion servicio (from servicio, evento, operacion y transaccion) nom bre : string 0..* protocolo operacion (from servicio, evento, operacion y transaccion) transaccion (from servi ci o, ev en to, op eracio n y tra ns acc o i n) Figura B.10: Paquete “procesos” 1 accion (from accion) 179 clase esq uema_conceptual (from clase,int erfaz y e_conceptual) (from clase,int erfaz y e_conceptual) nom br e : stri ng 1 1 1..* 0..* { ordenado} cli ente_ser vi dor param etr o_identificador cl ave_especial : str ing 0..1 0..* 0..* 0..1 cliente 1 identificador (from at ributo e identif icador) ser vidor 1 1 1 nom bre : stri ng 1 0..* 0..* 0..* acci on 0..* call_shar e 0..* (from servicio, event o, operacion y transaccion) i nter faz (f rom accion) (from clase,int erfaz y e_concept ual) atributos_todos : char ser vi cios_todos : char Figura B.11: Paquete “cliente-servidor” es quem a _c on c ept u al (fr om cl ase,inter faz y e_c onceptual) 1 0 .. * 0. .* 1 clie nte a cc ion 1 0. . * param e tro acc io n 0. . * ( fr om clie nte_ser vido r) 1 0. .* 1 s erv idor ( fr om c liente_ser vidor) s erv ic io (fr om ser vici o, evento , oper aci on y tr ansacci on) n om bre : s t ring Figura B.12: Paquete “acciones” 180 APÉNDICE B. REPOSITORIO OASIS esquem a_conceptual relacion 0..* 1 (from clase, int erfaz y e_concept ual) herencia agr egacion alias_com ponente : string card_m in_agregacion : char card_m ax_agregacion : char card_m in_com ponente : char card_m ax_com ponente : char lista_cadena_com ponentes : lista(string) lista_cadena_com puestas : lista(string) P : H erencia P : Agregacion Figura B.13: Paquete “relaciones” rela cion (from relacion) represent acion componente compuest a 1 0.. * c lase (f rom clase,int erfaz y e_concept ual) ag rega cio n 0.. * (from relacion) n omb re : st rin g 1.. * 0..* componente agregacion inclusiva 1 a ila s_componen te : strin g car d_min_agreg acion : char c ar d_ m ax _a gr eg acio n : ch ar card_min_component e : char c ar d_ m ax_compone nte : char list a_cadena_co mponent es : list a(st ring) list a _ca de na _c ompu es ta s : li st a( str n i g) ag re ga ci on rela cion al repr es en ta cion (from atributo e identif icador) rango inferior : string r an go s up er ior : strin g r eprese nt ac ion c omp ues t a 1 0. .* agregaci on d n i amic a agregacion est at ica card_max_componente > 1 grouping by asociacion condicion asociacion 0.. 1 1 0.. * Figura B.14: Paquete “agregacion” 1. .* atribut o (from at ributo e ident ificador) n omb re : st rin g c ar d_ m in : ch ar card_max : char val or _d ef ec to : st rin g 181 relac ion (from relacion) s ubc las e c las e herenc ia 0.. * (from relacion) 0. . * 1. .* (from clase,interfaz y e_ nom bre : s t ring 1 s uperc las e rol partic ion 0. .* 1. .* par t ic ion es tatica s erv ic io partic ion dinam ic a (from servicio, evento, operacion y transaccion) nom bre : s t ring part ic ion dinam ic a ev ento par tic ion di nam ic a at ri bu to 1 1 1.. * 1 rel aci on de m igra ci on c ondic ion es pec ializac ion Figura B.15: Paquete “herencia” 182 APÉNDICE B. REPOSITORIO OASIS fbf 0..1 op_izquierdo 0..1 0..1 op_derecho 0..1 operador : string atom o 1 operador 1 0..1 1 1 fbf tem poral tim eout : string delay : string unidad_tem p : string op_der echo op_izquierdo op_derecho 1 1 argum ento funcion {ordenado} term ino 0..1 op_ izquierdo 0..1 0..* 0.. 1 Am bito Form ula 0..1 funcion argum ento constan te atributo (f rom argu ment o) nom bre : string nro_orden : nat (f rom at ribut o e ident if icador) nom bre : string card_m in : char card_m ax : char valor_defecto : string Figura B.16: Paquete “fórmula” f bf fbf t em poral (from f orm ula) operador : st ring (from f orm ula) t im eout : string delay : string unidad_t em p : string rest riccion dinam ica (f rom restriccion) condicion evaluacion (f rom evaluacion) condicion especializacion (f ro m P : Her en ci a) condicion derivacion asignacion derivacion (from derivacion) asignacion evaluacion (from evaluacion) (f rom derivacion) guarda (from protocolo) condicion disparo (from disparo) condicion precondicion (from precondicion) restricc o i n estatic a (from restriccion) Figura B.17: Paquete “ámbito fórmula” condicion asociacion (from P : Agregacion) 183 term ino (from form ula) para metro nr o_o rde n : na t param etro_identificador param etro accion (from cliente_servidor) (from accion) param etro_alias_for param etro_call_share (from servicio, evento, operacion y transaccion) (from servicio, evento, operacion y transaccion) param etro operacion (from protocolo) Figura B.18: Paquete “parámetros” 184 APÉNDICE B. REPOSITORIO OASIS Apéndice C Plantillas para generar KL1 En este apéndice se presentan las plantillas establecidas para la generación de código KL1 a partir del repositorio OASIS. Se presentarán algunos de los predicados y cláusulas que dependen de la información del repositorio, es decir, aquellos que varían de un sistema a otro. Las plantillas completas, incluyendo los predicados de librería y sus respectivas cláusulas pueden consultarse en [49]. Notación utilizada Información extraida desde el repositorio (considerando que las mayúsculas, cuando se usan, son significativas). inicio/fin de constructor estructurado . comentario. C.1. Cláusulas para predicados main y router El predicado main permite arrancar el sistema estableciendo como submetas las clases del sistema y un objeto de la clase user que desempeñará el papel del analista. El predicado router encamina las acciones desde los clientes a los servidores. :- module main. main :take_active_actions(ActiveActions), UserActions=[action(c(tester),s(user),e(add,[att(userid,root)])) |RestUserActions], c_user(UserActions,UserTriggers,[att(population,[])]), PARA CADA CLASE c_clase(ClaseActions,ClaseTriggers,[att(population,[])]), FIN PARA generic:new(merge,{ActiveActions,UserTriggers, 185 186 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 PARA CADA CLASE ClaseTriggers separa r con “,” si hay m ás de u na },Actions), router(Actions,RestUserActions, PARA CADA CLASE ClaseActions separar FIN PARA )@lower_priority. con “,” si hay m ás de una %**************************************************************************** % router %**************************************************************************** PARA CADA CLASE router([action(this,s(clase,id(Id,Value)),e(Server,Event))|RestActions], PARA CADA CLASE ClaseActions separar con “,” si hay m ás de u na FIN PARA ) :ClaseActions=[action(this,s(clase,id(Id,Value)),e(Server,Event)) |RestClaseActions], router(RestActions, PARA CADA CLASE SI es la clase del bucle externo ENTONCES RestClaseActions separar con “,” si queda algu na SINO ClaseActions separar con “,” si queda algu na clase FIN SI clase FIN PARA )@lower_priority. FIN PARA router([action(Client,s(society,everyone),e(stop,[]))|RestActions], PARA CADA CLASE ClaseActions separar con “,” si hay m ás de u na FIN PARA ) :PARA CADA CLASE ClaseActions=[action(Client,s(society,everyone),e(stop,[]))] separar con “,” si queda una c lase, poner u n “.” despu és de la ú ltim a FIN PARA PARA CADA CLASE router([action(Client,s(clase),Event)|RestActions], PARA CADA CLASE ClaseActions separar con “,” si hay m ás de u na FIN PARA ) :ClaseActions=[action(Client,s(clase),Event)|RestClaseActions], router(RestActions, PARA CADA CLASE SI es la clase del bucle externo ENTONCES RestClaseActions separar con “,” si queda algu na SINO ClaseActions separar con “,” si queda algu na clase FIN SI FIN PARA )@lower_priority. FIN PARA clase C.1. CLÁUSULAS PARA PREDICADOS MAIN Y ROUTER PARA CADA CLASE router([action(Client,s(clase,everyone),Event)|RestActions], PARA CADA CLASE ClaseActions separar con “,” si hay m ás de u na FIN PARA ) :ClaseActions=[action(Client,s(clase,everyone),Event)|RestClaseActions], router(RestActions, PARA CADA CLASE SI es la clase del bucle externo ENTONCES RestClaseActions separar con “,” si queda algu na SINO ClaseActions separar con “,” si queda algu na clase FIN SI clase FIN PARA )@lower_priority. FIN PARA PARA CADA CLASE router([action(Client,s(clase,id(Id,Value)),Event)|RestActions], PARA CADA CLASE ClaseActions separar con “,” si hay m ás de u na FIN PARA ) :ClaseActions=[action(Client,s(clase,id(Id,Value)),Event)|RestClaseActions], router(RestActions, PARA CADA CLASE S I es la clas e d el b u cle ex tern o E N T O N C E S RestClaseActions separar con “,” si queda algu na clase S IN O ClaseActions separar con “,” si queda algu na clase F IN S I FIN PARA )@lower_priority. FIN PARA otherwise. router([Action|RestActions], PARA CADA CLASE ClaseActions separar FIN PARA ) :print_test_router(Action), router(RestActions, PARA CADA CLASE ClaseActions separar FIN PARA )@lower_priority. con “,” si hay m ás de u na con “,” si hay m ás de u na 187 188 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 C.1.1. Ejemplo: Código generado para los predicados main y router en el sistema bancario :- module main. 1 main :take_active_actions(ActiveActions), UserActions=[action(c(tester),s(user),e(add,[att(userid,root)])) |RestUserActions], c_user(UserActions,UserTriggers,[att(population,[])]), c_account(AccountActions,AccountTriggers,[att(population,[])]), c_customer(CustomerActions,CustomerTriggers,[att(population,[])]), generic:new(merge,{ActiveActions,UserTriggers, AccountTriggers,CustomerTriggers},Actions), router(Actions,RestUserActions,AccountActions,CustomerActions)@lower_priority. %**************************************************************************** % router %**************************************************************************** 2 router([action(this,s(user,id(Id,Value)),e(Server,Event))|RestActions], UserActions,AccountActions,CustomerActions) :UserActions=[action(this,s(user,id(Id,Value)),e(Server,Event)) |RestUserActions], router(RestActions,RestUserActions,AccountActions,CustomerActions )@lower_priority. router([action(this,s(account,id(Id,Value)),e(Server,Event))|RestActions], UserActions,AccountActions,CustomerActions) :AccountActions=[action(this,s(account,id(Id,Value)),e(Server,Event)) |RestAccountActions], router(RestActions,UserActions,RestAccountActions,CustomerActions )@lower_priority. router([action(this,s(customer,id(Id,Value)),e(Server,Event))|RestActions], UserActions,AccountActions,CustomerActions) :CustomerActions=[action(this,s(customer,id(Id,Value)),e(Server,Event)) |RestCustomerActions], router(RestActions,UserActions,AccountActions,RestCustomerActions )@lower_priority. 3 router([action(Client,s(society,everyone),e(stop,[]))|RestActions], UserActions,AccountActions,CustomerActions) :UserActions=[action(Client,s(society,everyone),e(stop,[]))], AccountActions=[action(Client,s(society,everyone),e(stop,[]))], CustomerActions=[action(Client,s(society,everyone),e(stop,[]))]. 4 router([action(Client,s(user),Event)|RestActions], UserActions,AccountActions,CustomerActions) :UserActions=[action(Client,s(user),Event)|RestUserActions], router(RestActions,RestUserActions,AccountActions,CustomerActions )@lower_priority. 1 El predicado main arranca la sesión de animación. Inmediatamente es creada la ínica instancia de usuario, que representa al analista y se encarga de introducir al sistema las acciones que éste genere a través de la interfaz de animación. Además se lanzan los subobjetivos que representan a cada una de las clases del sistema estableciendo la configuración de comunicación. El subobjetivo router se encarga de distribuir todas las acciones hacia las clases correspondientes. 2 Las tres siguientes cláusulas distribuyen las acciones que el analista introduce desempeñando el papel de algún objeto activo. 3 Esta cláusula se utiliza para distribuir la acción de término de la animación a todas las clases y objetos del sistema. 4 Las tres siguientes cláusulas distribuyen las acciones dirigidas a cada una de las clases. C.1. CLÁUSULAS PARA PREDICADOS MAIN Y ROUTER 189 router([action(Client,s(account),Event)|RestActions], UserActions,AccountActions,CustomerActions) :AccountActions=[action(Client,s(account),Event)|RestAccountActions], router(RestActions,UserActions,RestAccountActions,CustomerActions )@lower_priority. router([action(Client,s(customer),Event)|RestActions], UserActions,AccountActions,CustomerActions) :CustomerActions=[action(Client,s(customer),Event)|RestCustomerActions], router(RestActions,UserActions,AccountActions,RestCustomerActions )@lower_priority. 5 router([action(Client,s(user,everyone),Event)|RestActions], UserActions,AccountActions,CustomerActions) :UserActions=[action(Client,s(user,everyone),Event)|RestUserActions], router(RestActions,RestUserActions,AccountActions,CustomerActions )@lower_priority. router([action(Client,s(account,everyone),Event)|RestActions], UserActions,AccountActions,CustomerActions) :AccountActions=[action(Client,s(account,everyone),Event)|RestAccountActions], router(RestActions,UserActions,RestAccountActions,CustomerActions )@lower_priority. router([action(Client,s(customer,everyone),Event)|RestActions], UserActions,AccountActions,CustomerActions) :CustomerActions=[action(Client,s(customer,everyone),Event) |RestCustomerActions], router(RestActions,UserActions,AccountActions,RestCustomerActions )@lower_priority. 6 router([action(Client,s(user,id(Id,Value)),Event)|RestActions], UserActions,AccountActions,CustomerActions) :UserActions=[action(Client,s(user,id(Id,Value)),Event)|RestUserActions], router(RestActions,RestUserActions,AccountActions,CustomerActions )@lower_priority. router([action(Client,s(account,id(Id,Value)),Event)|RestActions], UserActions,AccountActions,CustomerActions) :AccountActions=[action(Client,s(account,id(Id,Value)),Event) |RestAccountActions], router(RestActions,UserActions,RestAccountActions,CustomerActions )@lower_priority. router([action(Client,s(customer,id(Id,Value)),Event)|RestActions], UserActions,AccountActions,CustomerActions) :CustomerActions=[action(Client,s(customer,id(Id,Value)),Event) |RestCustomerActions], router(RestActions,UserActions,AccountActions,RestCustomerActions )@lower_priority. otherwise. router([Action|RestActions],UserActions,AccountActions,CustomerActions) :print_test_router(Action), router(RestActions,UserActions,AccountActions,CustomerActions)@lower_priority. 5 Las tres siguientes cláusulas distribuyen las acciones enviadas en broadcast a todos los objetos de una clase. 6 Las tres siguientes cláusulas distribuyen las acciones enviadas a objetos específicos en alguna de las clases. 190 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 C.2. Cláusulas por cada clase Para cada clase del sistema (incluyendo la clase user) se generan los predicados c_clase y o_clase que permiten reducir los objetivos que representan a la clase y a sus instancias, respectivamente. A continuación se presenta la plantilla para el predicado c_clase y una pequeña parte de la plantilla del predicado o_clase. Como se verá, ambas plantillas son similares pues el tratamiento de objetos (procesos en ejecución) es homogéneo, sean estos clases o instancias. Sin embargo, la plantilla para el predicado o_clase es más simple y reducida porque la única acción que maneja una clase en ejecución es la acción de creación de objetos. C.2.1. Cláusulas para el predicado c_clase %*************************************************************************** % clase %************************************************************************** c_clase(Actions,Triggers,State) :7 Conflicts=[conflict(evento new,[evento new])], 8 TClassClase:=100000, clock(Stop,TClassClase,TickActions), generic:new(merge,{TickActions,Actions},Mbox), c_clase(TickActions,Stop,Mbox,Triggers,Conflicts,State,null)@lower_priority. c_clase(TickActions,true,Mbox,Triggers,Conflicts,State,OldState). alternatively. 9 c_clase([TickAction|RestTickActions],Stop,Mbox,Triggers,Conflicts, State,OldState) :1 0 wait(TickAction) | This=c(clase), extract(This,Mbox,RestMbox,TriggerActions,Services), get_object_actions(Services,ObjectActions,ServiceActions), send_object_actions(ObjectActions,State,NState,RejectedObjectActions), check_clase_conditions(ServiceActions,State,AcceptedActions, RejectedClassActions), concat_triggers(RejectedObjectActions,RejectedClassActions, TriggerActions,NTriggerActions), select_actions(Conflicts,NTriggerActions,AcceptedActions,ExecutedActions, ConflictActions), calculate_clase_new_state(ExecutedActions,NState,NNState,Triggers, NTriggers,Stop), send_triggers(This,NTriggerActions,NTriggers,RestTriggers), 7 Se establecen los conflictos. Para el caso de una clase cuyo único evento es el de creación, sólo tiene conflicto consigo mismo. 8 Se establece la frecuencia de los ticks en la vida de una clase. Se ha utilizado por defecto 100.000 microsegundos tanto para las clases como para sus instancias. En futuras versiones este parámetro podría ser establecido desde la interfaz de animación para ejercitar con distintas velocidades de trabajo de los objetos, permitiendo acumulación de acciones a ser procesadas. 9 En el cuerpo de esta cláusula se implementa el modelo de ejecución que controla la vida de cada clase y objeto. Esto se comentará en más detalle sobre el ejemplo que se presenta más adelante. 10 El objeto se reduce sólo cuando al menos se ha alcanzado el siguiente tick. C.2. CLÁUSULAS POR CADA CLASE 191 calculate_new_clase_triggers(NNState,MboxTriggers), calculate_next_mbox(RestMbox,MboxTriggers,ConflictActions,NextMbox), print_test_class(This,TickAction,NTriggerActions,ServiceActions, ConflictActions,ExecutedActions,State,OldState), c_clase(RestTickActions,Stop,NextMbox,RestTriggers,Conflicts, NNState,State)@lower_priority. %************************************************************************** % check_clase_conditions %************************************************************************** check_clase_conditions([],State,AcceptedActions,RejectedActions) :AcceptedActions=[], RejectedActions=[]. check_clase_conditions([Action|RestActions],State,AcceptedActions, RejectedActions) :check_one_clase_condition(Action,State,Result,Msg), check_action(Result,Msg,Action,AcceptedActions,RestAcceptedActions, RejectedActions,RestRejectedActions), check_clase_conditions(RestActions,State,RestAcceptedActions, RestRejectedActions)@lower_priority. %************************************************************************** % check_one_clase_condition %************************************************************************** 1 1 check_one_clase_condition(action(Client,This,e(evento new,Attributes)),State, Result,Msg) :get_attributes(Attributes,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA ]) get_attributes(State,[att(population,Population)]), get_oid(Found,Population,id(identificador,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA ]),OidObject), change_result(Found,Result), Msg=object_exists. check_one_clase_condition(action(Client,Server1,e(Server2,e(Event,Args))), State,Result,Msg) :Result=true, Msg=nothing. check_one_clase_condition(action(Client,This,e(tick,[I,T])),State,Result,Msg) :Result=true, Msg=nothing. check_one_clase_condition(action(Client,This,e(rejected,Action)),State, Result,Msg) :Result=true, Msg=nothing. check_one_clase_condition(action(Client,s(society,everyone),e(stop,[])), State,Result,Msg) :Result=true, Msg=nothing. 11 Esta cláusula verificará los permisos (prohibiciones) para el evento de creación. 192 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 otherwise. check_one_clase_condition(action(Client,This,Event),State,Result,Msg) :Result=false, Msg=service_unknown. %************************************************************************** % calculate_clase_new_state %************************************************************************** calculate_clase_new_state(ExecutedActions,State,NState,Triggers,NTriggers, Stop) :(wait(ExecutedActions);wait(State)) | verify_stop(ExecutedActions,Stop), execute_clase_actions(ExecutedActions,State,NState,Triggers,NTriggers). %************************************************************************** % execute_clase_actions %************************************************************************** execute_clase_actions([],State,NState,Triggers,NTriggers) :NState=State, NTriggers=Triggers. execute_clase_actions([Action|RestActions],State,NNState,Triggers,NNTriggers) :execute_one_clase_action(Action,State,NState,Triggers,NTriggers), execute_clase_actions(RestActions,NState,NNState,NTriggers, NNTriggers)@lower_priority. %************************************************************************** % execute_one_clase_action %************************************************************************** 1 2 execute_one_clase_action(action(Client,s(clase),e(evento_new,Attributes)),State, NState,Triggers,NTriggers) :get_attributes(State,[att(population,Population)]), Triggers={NTriggers,ObjectTriggers}, get_attributes(Attributes,[ PARA CADA ATRIBUTO USADO EN DERIVACION att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA ]), PARA CADA ATRIBUTO DERIVADO SI ATRIBUTO DERIVADO ES BOOLEAN Atributo derivado := expresión de derivación, SINO ExpIzq := expresión izquierda, ExpDer := expresión derecha, test_condition([[c(operador relacional,ExpIzq,ExpDer)]],Atributo derivado), FIN SI concat(Attributes,[att(atributo derivado,Atributo derivado)],NAttributes), 1 3 o_clase([action(Client,s(clase),e(evento new,Attributes))|Oid],ObjectTriggers, [att(destroy,false)|NAttributes]), get_attributes(NAttributes,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA ]), NPopulation=[object(Oid,[id(identificador,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA 12 13 Esta cláusula ejecuta la acción de creación de un objeto. Este subobjetivo representa al objeto creado. C.2. CLÁUSULAS POR CADA CLASE 193 ])])|Population], update_state(State,[chg(population,NPopulation)],NState). otherwise. execute_one_clase_action(action(Client,This,Event),State,NState,Triggers, NTriggers) :NState=State, NTriggers=Triggers. %************************************************************************** % calculate_new_clase_triggers %************************************************************************** calculate_new_clase_triggers(State,Triggers) :wait(State) | verify_clase_triggers([],State,Triggers). %************************************************************************** % verify_clase_triggers %************************************************************************** verify_clase_triggers([],State,Triggers) :Triggers=[]. C.2.2. Cláusulas para el predicado o_clase En esta parte de la plantilla no se incluyen las cláusulas específicas para el tratamiento de evaluaciones ni de disparos. Consultar en [49] por dichos aspectos. %*************************************************************************** % o_clase %************************************************************************** o_clase(Actions,Triggers,State) :Conflicts=[ PARA CADA SERVICIO conflict(servicio,[ Lista de servicios que afectan a un conjunto no disjunto de atributos respecto del servicio analizado. Si el servicio analizado es el new o destroy, incluir todos los servicios ]) poner “,” si qued an m ás servicios FIN PARA ], TObjectClase:=100000, clock(Stop,TObjectClase,TickActions), generic:new(merge,{TickActions,Actions},Mbox), o_clase(TickActions,Stop,Mbox,Triggers,Conflicts,State,null)@lower_priority. o_clase(TickActions,true,Mbox,Triggers,Conflicts,State,OldState). alternatively. o_clase([TickAction|RestTickActions],Stop,Mbox,Triggers,Conflicts,State, OldState) :wait(TickAction) | get_attributes(State,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR att(atributo,Atributo) poner “,” si q uedan m ás F IN PARA ]), This=c(clase,id(identificador,[ PARA CADA ATRIBUTO DEL IDENTIFICADOR 194 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 att(atributo,Atributo) poner “,” si q uedan m ás PARA ])), extract(This,Mbox,RestMbox,TriggerActions,ServiceActions), check_o_clase_conditions(ServiceActions,State,AcceptedActions, RejectedActions), concat(RejectedActions,TriggerActions,NTriggerActions), select_actions(Conflicts,NTriggerActions,AcceptedActions, ExecutedActions,ConflictActions), calculate_o_clase_new_state(ExecutedActions,State,NState,Stop), send_triggers(This,NTriggerActions,Triggers,RestTriggers), calculate_new_o_clase_triggers(NState,MboxTriggers), calculate_next_mbox(RestMbox,MboxTriggers,ConflictActions,NextMbox), print_test_object(This,TickAction,NTriggerActions,ServiceActions, ConflictActions,ExecutedActions,State,OldState), o_clase(RestTickActions,Stop,NextMbox,RestTriggers,Conflicts, NState,State)@lower_priority. F IN %************************************************************************** % check_o_clase_conditions %************************************************************************** check_o_clase_conditions([],State,AcceptedActions,RejectedActions) :AcceptedActions=[], RejectedActions=[]. check_o_clase_conditions([Action|RestActions],State,AcceptedActions, RejectedActions) :check_first_o_clase_condition(Action,State,Result,Msg), check_action(Result,Msg,Action,AcceptedActions,RestAcceptedActions, RejectedActions,RestRejectedActions), check_o_clase_conditions(RestActions,State,RestAcceptedActions, RestRejectedActions)@lower_priority. %************************************************************************** % check_first_o_clase_condition %************************************************************************** check_first_o_clase_condition(action(Client,s(society,everyone),e(stop,[])), State,Result,Msg) :Result=true, Msg=nothing. otherwise. check_first_o_clase_condition(Action,State,Result,Msg) :get_attributes(State,[att(destroy,Destroy)]), LExp1=Destroy, RExp1=false, test_condition([[c(eq,LExp1,RExp1)]],First), check_one_o_clase_condition(First,Action,State,Result,Msg). %************************************************************************** % check_one_o_clase_condition %************************************************************************** check_one_o_clase_condition(false,Action,State,Result,Msg) :Result=false, Msg=object_destroyed. PARA CADA EVENTO SI EVENTO TIENE PRECONDICION check_one_o_clase_condition(true,action(Client,This,e(evento, [lista parámetros])),State,Result,Msg) :get_attributes(State,[ PARA CADA ATRIBUTO USADO EN LA PRECONDICION att(pin,Pin) poner “,” si queda n m ás FIN PARA C.2. CLÁUSULAS POR CADA CLASE 195 ]), PARA CADA CONDICION EN LA PRECONDICION SI UNO DE LOS OPERANDOS ES BOOL ExpIzqi = expresión izquierda, ExpDeri = expresión derecha, SINO ExpIzqi := expresión izquierda, ExpDeri := expresión derecha, FIN SI FIN PARA test_condition([ PARA DISYUNCION DE CONDICIONES [ PARA CONDICION c(operador relacional,ExpIzqi ,ExpDeri ) poner “,” si q uedan m ás FIN PARA ] FIN PARA ],Result), Msg=not([ PARA DISYUNCION DE CONDICIONES [ PARA CONDICION c(operador relacional,ExpIzqi ,ExpDeri ) poner “,” si q uedan m ás FIN PARA ] FIN PARA ]). SINO check_one_o_clase_condition(true,action(Client,This,e(evento,Args)), State,Result,Msg) :Result=true, Msg=nothing. FIN SI FIN PARA check_one_o_clase_condition(true,action(Client,This,e(tick,[I,T])), State,Result,Msg) :Result=true, Msg=nothing. check_one_o_clase_condition(true,action(Client,This,e(rejected,Action)), State,Result,Msg) :Result=true, Msg=nothing. otherwise. check_one_o_clase_condition(true,action(Client,This,Event),State,Result,Msg) :Result=false, Msg=service_unknown. 196 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 C.2.3. Ejemplo: Código generado para los predicado c_account y o_account en el sistema bancario %*************************************************************************** % account %************************************************************************** c_account(Actions,Triggers,State) :Conflicts=[conflict(open,[open])], TClassAccount:=100000, clock(Stop,TClassAccount,TickActions), generic:new(merge,{TickActions,Actions},Mbox), c_account(TickActions,Stop,Mbox,Triggers,Conflicts, State,null)@lower_priority. c_account(TickActions,true,Mbox,Triggers,Conflicts,State,OldState). alternatively. c_account([TickAction|RestTickActions],Stop,Mbox,Triggers,Conflicts, State,OldState) :wait(TickAction) | This=c(account), extract(This,Mbox,RestMbox,TriggerActions,Services), 14 get_object_actions(Services,ObjectActions,ServiceActions), send_object_actions(ObjectActions,State,NState,RejectedObjectActions), check_account_conditions(ServiceActions,State,AcceptedActions, RejectedClassActions), concat_triggers(RejectedObjectActions,RejectedClassActions,TriggerActions, NTriggerActions), select_actions(Conflicts,NTriggerActions,AcceptedActions, ExecutedActions,ConflictActions), calculate_account_new_state(ExecutedActions,NState,NNState,Triggers, NTriggers,Stop), send_triggers(This,NTriggerActions,NTriggers,RestTriggers), calculate_new_account_triggers(NNState,MboxTriggers), calculate_next_mbox(RestMbox,MboxTriggers,ConflictActions,NextMbox), 1 5 print_test_class(This,TickAction,NTriggerActions,ServiceActions, ConflictActions,ExecutedActions,State,OldState), c_account(RestTickActions,Stop,NextMbox,RestTriggers,Conflicts, NNState,State)@lower_priority. %************************************************************************** % check_account_conditions %************************************************************************** check_account_conditions([],State,AcceptedActions,RejectedActions) :AcceptedActions=[], RejectedActions=[]. check_account_conditions([Action|RestActions],State,AcceptedActions, RejectedActions) :check_one_account_condition(Action,State,Result,Msg), check_action(Result,Msg,Action,AcceptedActions,RestAcceptedActions, RejectedActions,RestRejectedActions), check_account_conditions(RestActions,State,RestAcceptedActions, RestRejectedActions)@lower_priority. %************************************************************************** % check_one_account_condition %************************************************************************** check_one_account_condition(action(Client,This,e(open,Attributes)), State,Result,Msg) :get_attributes(Attributes,[att(number,Number)]), get_attributes(State,[att(population,Population)]), get_oid(Found,Population,id(number,[att(number,Number)]),OidObject), 14 Este objetivo se encarga de identificar las acciones que van dirigidas a las instancias de la clase y el siguiente subobjetivo las envía a sus canales de entrada correspondientes. 15 Este objetivo se encarga de informar al entorno de animación que el objeto (en este caso la clase) ha avanzado un tick en su vida. C.2. CLÁUSULAS POR CADA CLASE change_result(Found,Result), Msg=object_exists. check_one_account_condition(action(Client,Server1,e(Server2,e(Event,Args))), State,Result,Msg) :Result=true, Msg=nothing. check_one_account_condition(action(Client,This,e(tick,[I,T])),State, Result,Msg) :Result=true, Msg=nothing. check_one_account_condition(action(Client,This,e(rejected,Action)),State, Result,Msg) :Result=true, Msg=nothing. check_one_account_condition(action(Client,s(society,everyone),e(stop,[])), State,Result,Msg) :Result=true, Msg=nothing. otherwise. check_one_account_condition(action(Client,This,Event),State,Result,Msg) :Result=false, Msg=service_unknown. %************************************************************************** % calculate_account_new_state %************************************************************************** calculate_account_new_state(ExecutedActions,State,NState,Triggers,NTriggers, Stop) :(wait(ExecutedActions);wait(State)) | verify_stop(ExecutedActions,Stop), execute_account_actions(ExecutedActions,State,NState,Triggers,NTriggers). %************************************************************************** % execute_account_actions %************************************************************************** execute_account_actions([],State,NState,Triggers,NTriggers) :NState=State, NTriggers=Triggers. execute_account_actions([Action|RestActions],State,NNState,Triggers, NNTriggers) :execute_one_account_action(Action,State,NState,Triggers,NTriggers), execute_account_actions(RestActions,NState,NNState,NTriggers, NNTriggers)@lower_priority. %************************************************************************** % execute_one_account_action %************************************************************************** execute_one_account_action(action(Client,s(account),e(open,Attributes)),State, NState,Triggers,NTriggers) :get_attributes(State,[att(population,Population)]), Triggers={NTriggers,ObjectTriggers}, get_attributes(Attributes,[att(balance,Balance)]), ExpIzq1:=Balance, ExpDer1:=100, test_condition([[c(ge,ExpIzq1,ExpDer1)]],Good_balance), concat(Attributes,[att(good_balance,Good_balance)],NAttributes), o_account([action(Client,s(account),e(open,Attributes))|Oid],ObjectTriggers, [att(destroy,false)|NAttributes]), get_attributes(NAttributes,[att(number,Number)]), NPopulation=[object(Oid,[id(number,[att(number,Number)])])|Population], update_state(State,[chg(population,NPopulation)],NState). 197 198 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 otherwise. execute_one_account_action(action(Client,This,Event),State,NState,Triggers, NTriggers) :NState=State, NTriggers=Triggers. %************************************************************************** % calculate_new_account_triggers %************************************************************************** calculate_new_account_triggers(State,Triggers) :wait(State) | verify_account_triggers([],State,Triggers). %************************************************************************** % verify_account_triggers %************************************************************************** verify_account_triggers([],State,Triggers) :Triggers=[]. %************************************************************************** % o_account %************************************************************************** o_account(Actions,Triggers,State) :1 6 Conflicts=[ conflict(open,[open,close,deposit,withdraw,pay_commission,change_pin, change_rank]) ,conflict(close,[open,close,deposit,withdraw,pay_commission,change_pin, change_rank]) ,conflict(deposit,[open,close,deposit,withdraw,pay_commission]) ,conflict(withdraw,[open,close,deposit,withdraw,pay_commission]) ,conflict(pay_commission,[open,close,deposit,withdraw,pay_commission]) ,conflict(change_pin,[open,close,change_pin]) ,conflict(change_rank,[open,close,change_rank]) ], TObjectAccount:=100000, clock(Stop,TObjectAccount,TickActions), generic:new(merge,{TickActions,Actions},Mbox), o_account(TickActions,Stop,Mbox,Triggers,Conflicts, State,null)@lower_priority. o_account(TickActions,true,Mbox,Triggers,Conflicts,State,OldState). alternatively. o_account([TickAction|RestTickActions],Stop,Mbox,Triggers,Conflicts,State, OldState) :wait(TickAction) | get_attributes(State,[att(number,Number)]), This=c(account,id(number,[att(number,Number)])), extract(This,Mbox,RestMbox,TriggerActions,ServiceActions), 1 7 check_o_account_conditions(ServiceActions,State,AcceptedActions, RejectedActions), concat(RejectedActions,TriggerActions,NTriggerActions), 18 select_actions(Conflicts,NTriggerActions,AcceptedActions,ExecutedActions, ConflictActions), 1 9 calculate_o_account_new_state(ExecutedActions,State,NState,Stop), 20 send_triggers(This,NTriggerActions,Triggers,RestTriggers), 16 Para cada evento que puede proveer un objeto cuenta se establece una lista de los eventos que estarían en conflicto, es decir, no se ejecutarán en el mismo instante. 17 Verificación de los permisos (prohibiciones) de cada acción no obligada de proveer. 18 Identificación de las acciones que están en conflicto. 19 Ejecución del paso y obtención del nuevo estado. 20 Envío de acciones a otros objetos, asociadas a obligaciones por satisfacer en el estado actual. C.2. CLÁUSULAS POR CADA CLASE 199 2 1 calculate_new_o_account_triggers(NState,MboxTriggers), 2 2 calculate_next_mbox(RestMbox,MboxTriggers,ConflictActions,NextMbox), print_test_object(This,TickAction,NTriggerActions,ServiceActions, ConflictActions,ExecutedActions,State,OldState), o_account(RestTickActions,Stop,NextMbox,RestTriggers,Conflicts,NState, State)@lower_priority. %************************************************************************** % check_o_account_conditions %************************************************************************** check_o_account_conditions([],State,AcceptedActions,RejectedActions) :AcceptedActions=[], RejectedActions=[]. check_o_account_conditions([Action|RestActions],State,AcceptedActions, RejectedActions) :check_first_o_account_condition(Action,State,Result,Msg), check_action(Result,Msg,Action,AcceptedActions,RestAcceptedActions, RejectedActions,RestRejectedActions), check_o_account_conditions(RestActions,State,RestAcceptedActions, RestRejectedActions)@lower_priority. %************************************************************************** % check_first_o_account_condition %************************************************************************** check_first_o_account_condition(action(Client,s(society,everyone),e(stop,[])), State,Result,Msg) :Result=true, Msg=nothing. otherwise. 2 3 check_first_o_account_condition(Action,State,Result,Msg) :get_attributes(State,[att(destroy,Destroy)]), LExp1=Destroy, RExp1=false, test_condition([[c(eq,LExp1,RExp1)]],First), check_one_o_account_condition(First,Action,State,Result,Msg). %************************************************************************** % check_one_o_account_condition %************************************************************************** check_one_o_account_condition(false,Action,State,Result,Msg) :Result=false, Msg=object_destroyed. 2 4 check_one_o_account_condition(true,action(Client,This,e(withdraw, [XPin,XAmount])),State,Result,Msg) :get_attributes(State,[att(pin,Pin),att(balance,Balance),att(pin,Pin), att(balance,Balance),att(rank,Rank)]), ExpIzq1:=Pin, ExpDer1:=XPin, ExpIzq2:=Balance, ExpDer2:=XAmount, ExpIzq3:=Pin, ExpDer3:=XPin, ExpIzq4:=Balance, ExpDer4:=XAmount, ExpIzq5:=Rank, ExpDer5:=2, 21 Verificar las obligaciones que se satisfarán en el próximo estado alcanzado. Establecer el próximo buzón, incluyendo las acciones en conflicto no ejecutadas. 23 Se verifica una precondición por defecto que establece que para servir cualquier acción el objeto no debe estar destruido. 24 Se verifica la precondición: withdraw(Pin,Amount) if {(pin=Pin and balance >= Amount) or (pin=Pin and balance < Amount and rank=2)}. 22 200 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 test_condition([[c(eq,ExpIzq1,ExpDer1),c(ge,ExpIzq2,ExpDer2)], [c(eq,ExpIzq3,ExpDer3),c(lt,ExpIzq4,ExpDer4), c(eq,ExpIzq5,ExpDer5)]],Result), Msg=not([[c(eq,ExpIzq1,ExpDer1),c(ge,ExpIzq2,ExpDer2)], [c(eq,ExpIzq3,ExpDer3),c(lt,ExpIzq4,ExpDer4), c(eq,ExpIzq5,ExpDer5)]]). 25 check_one_o_account_condition(true,action(Client,This, e(change_pin,[XPin,XNewPin])),State,Result,Msg) :get_attributes(State,[att(pin,Pin)]), ExpIzq1:=Pin, ExpDer1:=XPin, test_condition([[c(eq,ExpIzq1,ExpDer1)]],Result), Msg=not([[c(eq,ExpIzq1,ExpDer1)]]). 2 6 check_one_o_account_condition(true,action(Client,This,e(close,[])),State, Result,Msg) :get_attributes(State,[att(balance,Balance)]), ExpIzq1:=Balance, ExpDer1:=0, test_condition([[c(eq,ExpIzq1,ExpDer1)]],Result), Msg=not([[c(eq,ExpIzq1,ExpDer1)]]). check_one_o_account_condition(true,action(Client,This,e(open,Args)),State, Result,Msg) :Result=true, Msg=nothing. check_one_o_account_condition(true,action(Client,This,e(deposit,Args)),State, Result,Msg) :Result=true, Msg=nothing. check_one_o_account_condition(true,action(Client,This,e(pay_commission,Args)), State,Result,Msg) :Result=true, Msg=nothing. check_one_o_account_condition(true,action(Client,This,e(change_rank,Args)), State,Result,Msg) :Result=true, Msg=nothing. check_one_o_account_condition(true,action(Client,This,e(tick,[I,T])),State, Result,Msg) :Result=true, Msg=nothing. check_one_o_account_condition(true,action(Client,This,e(rejected,Action)), State,Result,Msg) :Result=true, Msg=nothing. otherwise. check_one_o_account_condition(true,action(Client,This,Event),State, Result,Msg) :Result=false, Msg=service_unknown. %************************************************************************** % calculate_o_account_new_state %************************************************************************** calculate_o_account_new_state(ExecutedActions,State,NState,Stop) :25 26 Se verifica la precondición: change_pin(Pin,NewPin) if {pin=Pin}. Se verifica la precondición: close if {balance=0}. C.2. CLÁUSULAS POR CADA CLASE 201 verify_stop(ExecutedActions,Stop), execute_o_account_actions(ExecutedActions,State,NState). execute_o_account_actions([],State,NState) :NState=State. execute_o_account_actions([Action|RestActions],State,NNState) :execute_one_o_account_action(Action,State,NState), execute_o_account_actions(RestActions,NState,NNState)@lower_priority. %************************************************************************** % execute_one_o_account_action %************************************************************************** execute_one_o_account_action(action(Client,s(account),e(open,Attributes)), State,NState) :NState=State. execute_one_o_account_action(action(Client,This,e(close,[])),State,NState) :update_state(State,[chg(destroy,true)],NState). 2 7 execute_one_o_account_action(action(this,This,e(pay_commission,[])), State,NState) :get_attributes(State,[]), NTimes:=0, update_state(State,[chg(times,NTimes)],NState). otherwise. 28 execute_one_o_account_action(action(Client,This,e(deposit,[XAmount])), State,NState) :get_attributes(State,[att(balance,Balance),att(times,Times)]), NBalance:=Balance+XAmount, NTimes:=Times+1, ExpIzq1:=NBalance, ExpDer1:=100, test_condition([[c(ge,ExpIzq1,ExpDer1)]],NGood_balance), update_state(State,[chg(balance,NBalance),chg(times,NTimes), chg(good_balance,NGood_balance)],NState). 29 execute_one_o_account_action(action(Client,This,e(withdraw,[XPin,XAmount])), State,NState) :get_attributes(State,[att(balance,Balance),att(times,Times)]), NBalance:=Balance-XAmount, NTimes:=Times+1, ExpIzq1:=NBalance, ExpDer1:=100, test_condition([[c(ge,ExpIzq1,ExpDer1)]],NGood_balance), update_state(State,[chg(balance,NBalance),chg(times,NTimes), chg(good_balance,NGood_balance)],NState). 3 0 execute_one_o_account_action(action(Client,This,e(pay_commission,[])), State,NState) :get_attributes(State,[att(balance,Balance)]), NBalance:=Balance-1, ExpIzq1:=NBalance, ExpDer1:=100, test_condition([[c(ge,ExpIzq1,ExpDer1)]],NGood_balance), 27 Se efectúa la evaluación: [::pay_commision] times:=0. Nótese que esta acción es una obligación y en la especificación se distingue del servicio asociado al mismo evento anteponiendo “::”. En el programa KL1 se distingue utilizando como cliente “this”. 28 Esta cláusula realiza la evaluación: [deposit(Amount)] balance:= balance + Amount, times:= times + 1. 29 Aquí se efectúa la evaluación: [withdraw(Pin,Amount)] balance:= balance Amount, times:= times + 1. 30 Esta cláusula efectúa la evaluación: [pay_commision] balance:= balance - 1. 202 APÉNDICE C. PLANTILLAS PARA GENERAR KL1 update_state(State,[chg(balance,NBalance),chg(good_balance,NGood_balance)], NState). 3 1 execute_one_o_account_action(action(Client,This,e(change_pin,[XPin,XNewPin])), State,NState) :get_attributes(State,[]), NPin:=XPin, update_state(State,[chg(pin,NPin)],NState). 3 2 execute_one_o_account_action(action(Client,This,e(change_rank,[XRank])), State,NState) :get_attributes(State,[]), NRank:=XRank, update_state(State,[chg(rank,NRank)],NState). otherwise. execute_one_o_account_action(action(Client,This,Event),State,NState) :NState=State. %************************************************************************** % calculate_new_o_account_triggers %************************************************************************** calculate_new_o_account_triggers(State,Triggers) :verify_o_account_triggers([t1],State,Triggers). %************************************************************************** % verify_o_account_triggers %************************************************************************** verify_o_account_triggers([],State,Triggers) :Triggers=[]. 33 31 verify_o_account_triggers([t1|RestTriggers],State,Triggers) :get_attributes(State,[att(times,Times),att(good_balance,Good_balance), att(rank,Rank)]), ExpIzq1:=Times, ExpDer1:=5, ExpIzq2=Good_balance, ExpDer2=false, ExpIzq3:=Rank, ExpDer3:=0, test_condition([[c(ge,ExpIzq1,ExpDer1),c(eq,ExpIzq2,ExpDer2), c(eq,ExpIzq3,ExpDer3)]],Answer), put_trigger(Answer,action(this,self,e(pay_commission,[])), Triggers,NTriggers), verify_o_account_triggers(RestTriggers,State,NTriggers)@lower_priority. Esta cláusula realiza la evaluación: [change_pin(Pin,NewPin)] pin:= NewPin. En esta cláusula se realiza la evaluación: [change_rank(Rank)] rank:= Rank. 33 Es esta cláusula se verifica la condición de disparo: ::pay_commision when {times>=5 and good_balance=false and rank=0}. 32 Apéndice D Una sesion con entrada por lotes A continuación se presenta una sesión de animación con el prototipo en modo de entrada por lotes (batch). Las acciones son leidas desde el fichero test.dat y los resultados (las acciones acontecidas a los objetos y los respectivos estados alcanzados) son almacenados en el fichero test.res. El contenido del fichero se ha formateado y resumido en tablas. En este modo de trabajo, el analista valida manualmente el comportamiento esperado del sistema respecto al comportamiento exhibido por el prototipo. El fichero test.dat utilizado en este ejemplo es el siguiente: action(c(user),s(account),e(open,[att(number,101),att(name,pato), att(balance,0),att(counter,0),att(rank,0)])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[10])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[30])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[20])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[30])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[40])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[10])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[20])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[30])). action(c(user),s(account),e(open,[att(number,101),att(name,pato),att(balance,0), att(counter,0),att(rank,0)])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[40])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[10])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[20])). action(c(user),s(account,id(number,[att(number,101)])),e(change_rank,[1])). action(c(user),s(account),e(open,[att(number,202),att(name,bicho),att(balance,0), att(counter,0),att(rank,0)])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[30])). action(c(user),s(account,id(number,[att(number,202)])),e(deposit,[40])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[20])). action(c(user),s(account,id(number,[att(number,202)])),e(withdraw,[30])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[40])). action(c(user),s(account,id(number,[att(number,101)])),e(deposit,[30])). action(c(user),s(account,id(number,[att(number,202)])),e(deposit,[40])). action(c(user),s(account,id(number,[att(number,202)])),e(withdraw,[20])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[30])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[40])). action(c(user),s(account,id(number,[att(number,101)])),e(change_rank,[2])). action(c(user),s(account,id(number,[att(number,202)])),e(withdraw,[30])). action(c(user),s(account,id(number,[att(number,202)])),e(close,[])). 203 204 APÉNDICE D. UNA SESION CON ENTRADA POR LOTES action(c(user),s(account,id(number,[att(number,202)])),e(withdraw,[10])). action(c(user),s(account,id(number,[att(number,101)])),e(withdraw,[40])). action(c(user),s(account,id(number,[att(number,202)])),e(deposit,[40])). Cada una de las siguientes tablas, formateadas a partir del fichero test.res, reflejan el comportamiento exhibido por uno de los objetos durante la prototipación y ante la aplicación de las acciones en el fichero test.dat. Se han omitido los intervalos de tiempo en los cuales no se produjo algún cambio en el objeto. i Clase Account i i Services Conflicts i (ti-1 - ti] t0 Population Triggers - tick open(...101...) - (t8 - t9] 101 open(...101...) - (t14 - t15] 101 tick reject(open(10)) tick open(...202...) - (t35 - t36] 101,202 tick stop - i i+1 Executed Population tick open(101) tick reject(open(101)) tick open(202) tick stop 101 101 101,202 101,202 En t9 se rechazada la acción de creación de la cuenta 101 porque ya existe una cuenta con dicho valor identificador. Object Account 101 Servicesi Conflictsi (ti-1 - ti] t0 Statei Triggersi Executedi Statei+1 - tick open(...101...) deposit(10) deposit(10) tick open(101) (t0 - t1] destroy: false number: 101 name: pato balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 10 times: 0 rank: 0 good_balance: false tick deposit(10) - tick deposit(10) tick rejected(wit hdraw(30)) deposit(20) withdraw(30) - tick deposit(20) rejected(withdr aw(30)) destroy: false number: 101 name: pato balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 10 times: 1 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 30 times: 2 rank: 0 good_balance: false (t1 - t2] 205 (t3 - t4] (t4 - t5] (t5 - t6] (t6 - t7] (t7 - t8] (t8 - t9] (t10 - t11] (t11 - t12] destroy: false number: 101 name: pato balance: 30 times: 2 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 60 times: 3 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 100 times: 4 rank: 0 good_balance: true destroy: false number: 101 name: pato balance: 90 times: 5 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 90 times: 0 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 70 times: 1 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 40 times: 2 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 39 times: 2 rank: 0 good balance: false tick deposit(30) deposit(40) tick deposit(40) withdraw(10) tick withdraw(10) tick self::pay_co mmision withdraw(20) withdraw(30) tick withdraw(20) withdraw(30) tick withdraw(30) tick pay_commision tick rejected(wit hdraw(40) withdraw(40) deposit(10) deposit(20) deposit(40) tick deposit(30) destroy: false number: 101 name: pato balance: 60 times: 3 rank: 0 good_balance: false withdraw(10) tick destroy: false deposit(40) number: 101 name: pato balance: 100 times: 4 rank: 0 good balance: true tick destroy: false withdraw(10) number: 101 name: pato balance: 90 times: 5 rank: 0 good balance: false withdraw(20) destroy: false tick withdraw(30) self::pay_comm number: 101 name: pato ision balance: 90 times: 0 rank: 0 good_balance: false withdraw(30) tick destroy: false withdraw(30) number: 101 name: pato balance: 70 times: 1 rank: 0 good_balance: false tick destroy: false withdraw(30) number: 101 name: pato balance: 40 times: 2 rank: 0 good_balance: false tick destroy: false pay commision number: 101 name: pato balance: 39 times: 2 rank: 0 good_balance: false destroy: false deposit(20) tick rejected(withdr number: 101 name: pato aw(40)) deposit(10) balance: 49 times: 3 rank: 0 good balance: false En t6 times=5,good_balance=false y rank=0 con lo cual se satisface la condición de disparo para la acción ::pay_commision. En el mismo tick, los eventos withdraw(20) y withdraw(30) están en conflicto con pay_commision (todos ellos afectan el atributo balance) por lo tanto son postergados para el siguiente tick. 206 APÉNDICE D. UNA SESION CON ENTRADA POR LOTES (t12 - t13] destroy: false tick deposit(20) - (t13 - t14] tick change_rank(1) - tick deposit(30) - tick withdraw(20) - tick withdraw(40) - tick deposit(30) - tick withdraw(30) - tick rejected(wit hdraw(40) withdraw(40) change_rank(2) - (t14 - t15] (t22 - t23] (t26 - t27] (t28 - t29] (t30 - t31] (t32 - t33] number: 101 name: pato balance: 49 times: 3 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 69 times: 4 rank: 0 good_balance: false destroy: false number: 101 name: pato balance: 69 times: 4 rank: 1 good_balance: false destroy: false number: 101 name: pato balance: 99 times: 5 rank: 1 good_balance: false destroy: false number: 101 name: pato balance: 79 times: 6 rank: 1 good_balance: false destroy: false number: 101 name: pato balance: 39 times: 7 rank: 1 good_balance: false destroy: false number: 101 name: pato balance: 69 times: 8 rank: 1 good_balance: false destroy: false number: 101 name: pato balance: 39 times: 9 rank: 1 good balance: false tick deposit(20) destroy: false number: 101 name: pato balance: 69 times: 4 rank: 0 good_balance: false tick destroy: false change rank(1) number: 101 name: pato balance: 69 times: 4 rank: 1 good_balance: false tick destroy: false deposit(30) number: 101 name: pato balance: 99 times: 5 rank: 1 good_balance: false tick destroy: false withdraw(20) number: 101 name: pato balance: 79 times: 6 rank: 1 good_balance: false tick destroy: false withdraw(40) number: 101 name: pato balance: 39 times: 7 rank: 1 good_balance: false tick destroy: false deposit(30) number: 101 name: pato balance: 69 times: 8 rank: 1 good_balance: false tick destroy: false withdraw(30) number: 101 name: pato balance: 39 times: 9 rank: 1 good_balance: false tick destroy: false rejected(withdr number: 101 aw(40)) name: pato change rank(2) balance: 39 times: 9 rank: 2 good balance: false 207 (t36 - t37] destroy: false tick withdraw(40) - tick withdraw(40) (t38 - t39] number: 101 name: pato balance: 39 times: 9 rank: 2 good_balance: false destroy: false number: 101 name: pato balance: -1 times: 10 rank: 2 good_balance: false tick stop - tick stop Statei Triggersi - tick open(...202...) (t4 - t5] destroy: false tick deposit(40) - tick deposit(40) (t9 - t10] tick withdraw(30) - tick withdraw(30) tick deposit(40) - tick deposit(40) tick withdraw(20) - tick withdraw(20) (ti-1 - ti] t0 (t13 t14] (t15 t16] number: 202 name: bicho balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 40 times: 1 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 10 times: 2 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 50 times: 3 rank: 0 good_balance: false Object Account 202 Servicesi Conflictsi destroy: false number: 101 name: pato balance: -1 times: 10 rank: 2 good_balance: false destroy: false number: 101 name: pato balance: -1 times: 10 rank: 2 good_balance: false Executedi Statei+1 tick open(202) destroy: false number: 202 name: bicho balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 40 times: 1 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 10 times: 2 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 50 times: 3 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 30 times: 4 rank: 0 good_balance: false 208 APÉNDICE D. UNA SESION CON ENTRADA POR LOTES (t19- t20] destroy: false tick rejected(clo se) close withdraw(30) (t20- t21] tick self::pay_co mmision - - tick rejected(wit hdraw(10)) withdraw(10) - tick deposit(40) stop stop tick pay_commision stop - (t21 t22] (t23 t24] (t24 t25] number: 202 name: bicho balance: 30 times: 4 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 0 times: 5 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 0 times: 0 rank: 0 good_balance: false destroy: false number: 202 name: bicho balance: 40 times: 1 rank: 0 good_balance: false tick withdraw(30) destroy: false number: 202 name: bicho balance: 0 times: 5 rank: 0 good_balance: false tick destroy: false self::pay_comm number: 202 ision name: bicho balance: 0 times: 0 rank: 0 good_balance: false tick destroy: false rejected(withdr number: 202 aw(10) name: bicho balance: 0 times: 0 rank: 0 good_balance: false tick destroy: false deposit(40) number: 202 name: bicho balance: 40 times: 1 rank: 0 good_balance: false destroy: false tick pay commision number: 202 stop name: bicho balance: 39 times: 1 rank: 0 good_balance: false Bibliografía [1] Agha G.A. ACTORS: A Model of Concurrent Computation in Distributed Systems. The MIT Press, 1986. [2] Åqvist L. Deontic Logic. In D.M. Gabbay and F.Guenthner (Eds.), Handbook of Philosophical Logic II, pages 605-714, Reidel, 1984. [3] Balzer R., Cheatham T.E. Green C. Software Technology in the 1990’s: Using a New Paradigm. IEEE Computer, pages 39-45, November 1983. [4] Balzer R. A 15 Year Perspective on Automatic Programming. IEEE Transactions on Software Engineering, vol.11, num.11, pages 1257-1268, November 1985. [5] Bell R. Code Generation from Object Models. Embedded Systems Programming, March 1998. http://www.embedded.com/98/9803fe3.html. [6] Boer F.S., Kok J., Palamidessi C. On the Asynchronous Nature of Communication in Concurrent Logic Languages: A Fully Abstract Model based on Sequences. In J.C.Baeten and J.W.Klop (Eds.), CONCUR’90, pages 99-114, Springer-Verlag, 1990. [7] Börger E., Riccobene E. Logical Operational Semantics of Parlog, Part I: And-Parallelism. In Harold Boley, Michael M. and Richter (Eds.), International Workshop on Processing Declarative Knowledge, PDK’91, LNCS 1567, pages 191-198, Springer-Verlag, 1991. [8] Börger E., Riccobene E. Logical Operational Semantics of Prolog. Part II: Or-Parallelism. In Andrei Voronkov (Ed.), Proceedings of First Russian Conference on Logic Programming, LNCS 592, pages 27-34, Springer-Verlag, 1990. [9] Boehm B.W. Software Engineering: R & D Trends and Defense Needs. In Wegner, P. (Ed.), Research Directions in Software Technology, Cambridge MA: MIT Press, 1979. 209 210 BIBLIOGRAFÍA [10] Booch G. Análisis y Diseño Orientado a Objetos con Aplicaciones. Addison-Wesley/Díaz de Santos, 1996. [11] Coleman D., Hayes F., Bear S. Introducing Objectcharts or How to use Statecharts in Object-Oriented Design. IEEE Transactions on Software Engineering, vol.18, num.1, January 1992. [12] Conlon T. Programming in PARLOG. Addisson-Wesley, 1989. [13] Corchuelo R., Ruiz D., Toro M., Arjona J. and Prieto M. Prototyping IPC on a Network Computer. Proceedings of the IV MENHIR Workshop, pages 41-45, Burgos, 1999. [14] Chikayama, T. KLIC User’s Manual. Institute for New Generation Computer Tecnology, Tokyo, March 1995. [15] Craigen D., Gerhart S., Ralston T. Formal Methods Reality Check: Industrial Usage. IEEE Transactions on Software Engineering, vol.21, num.2, pages 90-98, February 1995. [16] Davis A. Software Requirements: Objects, Functions, and States. Prentice Hall International, 1993. [17] Davis A., Hsia P. Giving Voice to Requirements Engineering. IEEE Software, pages 12-16, March 1994. [18] Davison A. Polka: A Parlog Object-Oriented Language. PhD Thesis, Departament of Computer Science, Imperial Collegue Londres, 1989. [19] Dubois E., Du Bois P., Petit M. O-O Requirements Analysis: An Agent Perspective. In Proceedings of the 7th.European Conference on Object Oriented Programming, ECOOP’93, pages 458-481, 1993. [20] Dubois E., Hagelstein J., Rifaut A. A Formal Language for the Requirements Engineering of Computer Systems. In André Thayse (Ed.), From Natural Language Processing to Logic for Expert Systems, chapter 6, Wiley, 1991. [21] Dubois E., Du Bois P., Dubru F. Animating Formal Requirements Specifications of Cooperative Information Systems. In Proceedings of the Second International Conference on Cooperative Information Systems, pages 101-112, Toronto, Mayo 1994. [22] Feenstra R.B., Wieringa R.J. LCM 3.0: A Languaje for Describing Conceptual Models. Technical Report IR-344, Faculty of Mathematics and Computer Science, Vrije Universiteit, Amsterdam, 1993. BIBLIOGRAFÍA 211 [23] Filippidou, D. and P. Loucopoulos. Using Scenarios to Validate Requirements in a Plausibility-centred Approach. In Proceedings of the 9th International Conference on Advanced Information Systems Engineering, CAiSE’97, pages 47-60, Barcelona, 1997. [24] Fuchs N. Specifications are (Preferably) Executable. Software Engineering Journal, September 1992. [25] Garlan D., Perry D.E. Introduction to the Special Issue on Software Architecture. IEEE Transactions on Software Engineering, vol.21, num.4, pages 269-274, April 1995. [26] Gogolla M., Conrad S., Denker G., Herzig R., Vlachantonis N. A Development Environment for an Object Specification Language. IEEE Transactions on Knowledge and Data Engineering, vol.7, num.3, pages 505— 508, June 1995. [27] Goldsack S.J., Kent S.J.H. (Eds). Formal Methods and Object Technology. Springer-Verlag, 1996. [28] Grau A. Validating Object-Oriented Specifications through Animation. Workshop “Grundlagen von Datenbanken”, Workshop des GIArbeitskreises in Königslutter, Technischer Bericht, Universität Dortmund, pages 26-30, May 1997. [29] Hammer M., McLeod D. Database Descriptions with SDM: A Semantic Database Model. ACM Transactions on Database Systems, vol.6, num.3, pages 251-386, September 1981. [30] Harel D. Dynamic Logic. D.M.Gabbay, F.Guenthner (Eds.), Handbook of Philosophical Logic II, pages 497-694, Reidel 1984. [31] Harel D., Gery E. Executable Object Modeling with Statecharts. IEEE Computer, vol.30, num.7, pages 31-42, July 1996. [32] Hartmann T., Saake G. Abstract Specification of Object Interaction. Informatik-Bericht 93-08, TU Braunschweig, 1993. [33] Hartmann T., Jungclaus R., Saake G. Animation Support for a Conceptual Modelling Language. V. In Proc. of the 4th Int. Conf. on Database and Expert Systems Applications, DEXA’93, LNCS 720, pages 56—67, Springer-Verlag, Prague, September 1993. [34] Haumer P., Heymans P., Pohl K. An Integration of Scenario-Based Requirements Elicitation and Validation Techniques. Technical Report CREWS 98-28, Cooperative Requirements Engineering with Scenarios, 212 BIBLIOGRAFÍA ftp://sunsite.informatik.rwth-aachen.de/pub/CREWS/reports98.html. [35] Hayes I.J., Jones C.B. Specifications are Not (Necessarily) Executable. Technical Report Nro.148, Key Centre for Software Technology, Departament of Computer Science, University of Queensland, 1990. [36] Herzig R., Gogolla M. An Animator for the Object Specification Language TROLL Light. In Proceedings of the Colloquium on Object Orientation in Databases and Software Engineering, COODBSE’94, pages 156-170, Montreal, May1994. [37] Heymans P. Some Thoughts about the Animation of Formal Specifications written in the ALBERT II Language. Technical Report CREWS 97-04, Cooperative Requirements Engineering with Scenarios, http://sunsite.informatik.rwth-aachen.de/CREWS/reports97.html. [38] Heymans P. The Albert II Specification Animator. Technical Report CREWS 97-13, Cooperative Requirements Engineering with Scenarios, http://sunsite.informatik.rwth-aachen.de/CREWS/reports97.html. [39] Hinchey M.G., Bowen J.P. To Formalize or Not to Formalize?. In “An Invitation to Formal Methods”, IEEE Computer, vol.29, num.4, pages 18-19, April 1996. [40] Hull R., King R. Semantic Database Modelling. ACM Computing Surveys, vol.19, n.3, September 1987. [41] Jackson M. System Development. Prentice-Hall, 1983. [42] Jacobson I., Christerson M., Jonsson P., Övergaard G. Object-Oriented Software Engineering: A Use Case Driven Approach. ACM Press y Addison-Wesley, 1992. [43] Jungclaus R., Saake G., Hartmann T., Sernadas C. TROLL - A Language for Object-Oriented Specification of Information Systems. ACM Transactions on Information Systems, vol.14, num.2, pages 175-211, April 1995. [44] Koskimies K., Systä T., Tuomi J., Männistö T. Automated Support for Modelling OO Software. IEEE Software, pages 87-94, January 1998. [45] LaBudde E. Why is Requirements Engineering Underused?. IEEE Software, pages 6-8, March 1994. BIBLIOGRAFÍA 213 [46] Letelier P., Sánchez P., Ramos I. Conceptos Básicos de Especificaciones OASIS Implementados usando Progamación Lógica Concurrente. Informe Técnico DSIC-II/32/96, DSIC-Universidad Politécnica de Valencia, 1996. [47] Letelier P., Ramos I. Un Metamodelo Estático para Especificaciones OASIS y su Implementación en una Base de Datos Relacional. Informe Técnico DSIC-II/19/96, DSIC-Universidad Politécnica de Valencia, 1996. [48] Letelier P., Sánchez P., Ramos I. Modelización de la Perspectiva Cliente en Especificaciones OASIS. Informe Técnico DSIC-II/9/97, DSICUniversidad Politécnica de Valencia, 1997. [49] Letelier P., Sánchez P., Ramos I. Guías para la Generación Automática de un Programa Lógico Concurrente que sirve de Prototipo para una Especificación OASIS. Informe Técnico DSIC-II/26/97, DSIC-Universidad Politécnica de Valencia, 1997. [50] Letelier P., Sánchez P., Ramos I. Animación de Modelos Conceptuales para Ayudar en la Validación de Requisitos. In Proceedings of Argentine Symposium on Object Orientation, ASOO´97, páginas 100-110, Buenos Aires, Argentina, 1997. [51] Letelier P., Sánchez P., Ramos I. Animation of System Specifications using Concurrent Logic Programming. Symposium on Logical Approaches to Agent Modeling and Design, ESSLLI’97, Aix-en-Provence, France, 1997. [52] Letelier P., Sánchez P., Ramos I. Un Modelo Abstracto para la Ejecución de Especificaciones OASIS 3.0. Actas de las II Jornadas de Trabajo MENHIR, páginas 63-74, Murcia, 1998. [53] Letelier P., Sánchez P., Ramos I., Pastor O. Formalización de OASIS en Lógica Dinámica incluyendo Especificaciones de Proceso. Informe Técnico DSIC-II/2/98, Universidad Politécnica de Valencia, 1998. [54] Letelier P., Sánchez P., Ramos I. Animación de Especificaciones OASIS en Entornos Concurrentes. Actas de las II Jornadas de Trabajo de MENHIR, páginas 121-134, Valencia, 1998. [55] Letelier P., Sánchez P., Ramos I.. Especificaciones de Proceso para Objetos y su Representación en Lógica Dinámica. Actas de las III Jornadas de Ingeniería del Software, JIS’98, páginas 281-292, Murcia, 1998. 214 BIBLIOGRAFÍA [56] Letelier P., Sánchez P., Ramos I., Pastor O. OASIS versión 3.0: Un Enfoque Formal para el Modelado Conceptual Orientado a Objeto. Servicio de Publicaciones de la Universidad Politécnica de Valencia, SPUPV98.4011, 1998. [57] Letelier P., Sánchez P., Ramos I. Prototyping a Requirements Specification Through an Automatically Generated Concurrent Logic Program. In Gopal Gupta (Ed.), Practical Aspects of Declarative Languages, LCNS 1551, pages 31-45, Springer-Verlag, Texas, USA, 1998. [58] Letelier P., Sánchez P., Ramos I. Un Ambiente para Especificacion Incremental y Validacion de Modelos Conceptuales. Actas del 2o Workshop Iberoamericano de Ingeniería de Requisitos y Ambientes Software, IDEAS’99, páginas 216-228, Costa Rica, 1999. [59] Letelier P., Sánchez P., Ramos I. Animation of Conceptuals Models using two Concurrent Environments: An overview. Por publicar en Proceedings of 3rd IMACS/IEEE International Multiconference on Circuits, Systems, Communication and Computers, Grecia, 1999. [60] Luqi, Goguen J.A. Formal methods: Promises and Problems. IEEE Software, pages 73-85, January 1997. [61] Maiden N.A.M. CREWS-SAVRE: Scenarios for Acquiring and Validating Requirements. Technical Report CREWS 9803, Cooperative Requirements Engineering with Scenarios, http://sunsite.informatik.rwth-aachen.de/CREWS/reports98.html. [62] Martin J., Odell J. Object-Oriented Methods: A Foundation. Prentice Hall, 1998. [63] Participantes del Proyecto Menhir. MENHIR: Modelos, Entornos y Nuevas Herramientas para la Ingeniería de Requisitos. Actas de las III Jornadas de Investigación y Docencia en Bases de Datos, JIDBD’98, Valencia, 1998. [64] Meyer J.-J.Ch. A Different Approach to Deontic Logic: Deontic Logic viewed as a Variant of Dynamic Logic. In Notre Dame Journal of Formal Logic, vol.29, pages 109-136, 1988. [65] Milner R. Communication and Concurrency. C.A.R. Hoare Series Editor, Prentice Hall Series in Computer Science, 1989. BIBLIOGRAFÍA 215 [66] National Aeronautics and Space Administration (NASA). Formal Methods Specification and Verification Guidebook for Software and Computer Systems. Volume I: Planning and Technology Insertion, NASA-GB-00295 release 1.0, 1995, http://www.ivv.nasa.gov. [67] OBLOG Software S.A. The OBLOG Software Development Approach (White Paper). 1999, http://www.oblog.pt/Download/Documentation.exe [68] Ousterhout J. Tcl and the Tk Toolkit. Addison-Wesley, 1994. [69] Pastor O. Diseño y Desarrollo de un Entorno de Producción Automática de Software basado en el modelo OO. Tesis Doctoral, DSIC-UPV, 1992. [70] Pastor O., Ramos I. OASIS versión 2 (2.2) : A Class-Definition Language to Model Information Systems Using an Object-Oriented Approach. Servicio de Publicaciones Universidad Politécnica de Valencia, SPUPV-95.788, 1995. [71] Pastor O., Pelechano V., Romero J. y Barberá J.M. Descripción del Entorno Gráfico de la Herramienta CASE OO-METHOD. Informe Técnico ITI-UPV, 1996. [72] Pastor O., Insfrán E., Pelechano V., Romero J., Merseguer J. OOMETHOD: An OO Software Production Environment Combining Conventional and Formal Methods. Proceedings of Conference on Advanced Information Systems Engineering, CAiSE ’97, pages 145-158, Barcelona, 1997. [73] Pastor O., Pelechano V., Insfrán E. and Gómez J. From Object Oriented Conceptual Modeling to Automated Programming in Java. In Proceedings of 17th International Conference on Conceptual Modeling, ER’98, pages 183-196, Singapur, 1998. [74] Pimentel E. L2||O2: Un Lenguaje Lógico Concurrente Orientado a Objetos. Tesis Doctoral, Facultad de Informática, Universidad de Málaga, 1993. [75] Pohl K. Requirements Engineering: An Overview. Encyclopedia of Computer Science and Technology, A. Kent, J. Williams (Eds.), vol.36, supplement 21, Marcel Dekker, Inc., New York, 1997. [76] Popkin Software & Systems. The User Guide for the System Architect Family of Tools. 1997. 216 BIBLIOGRAFÍA [77] Proyecto ESPILL. Un Modelo Estático para Especificaciones OASIS v.3 y su Implementación en una Base de Datos Relacional. Informe Técnico DSIC-II/1/99, DSIC-Universidad Politécnica de Valencia, 1999. [78] Rational Software Corporation. UML Notation Guide. Versión 1.1. September 1997, http://www.rational.com/uml. [79] Rational Software Corporation. Manual of Rational Rose 98: Using Rose C++, 1998. [80] Rolland C., Ben Achour C., Cauvet C., Ralyté J., Sutcliffe A., Maiden N.A.M., Jarke M., Haumer P., Pohl K., Dubois E., Heymans P. A Proposal for a Scenario Classification Framework. Technical Report CREWS 96-01, Cooperative Requirements Engineering with Scenarios, http://sunsite.informatik.rwth-aachen.de/CREWS/reports96.html. [81] Rumbaugh J., Blaha M., Premerlani W., Eddy F., Lorenzen W. ObjectOriented Modeling and Design. Prentice Hall, 1991. [82] Sánchez P., Letelier P., Ramos I. Representación de Objetos en Teorías y su Traducción a un Modelo de Concurrencia. Revista Computación y Sistemas, vol.1, núm.2, páginas 101-111, 1997. [83] Sánchez P., Letelier P., Ramos I., Pastor O. Modelado Conceptual con un Lenguaje Formal y Orientado a Objeto. Por aparecer en Actas de la XXV Conferencia Latinoamericana de Informática, CLEI’99, Asunción, Agosto 1999. [84] Shapiro E., Takeuchi A. Object Oriented Programming in Concurrent Prolog. New Generation Computing, vol.1, pages 25-48, 1983. [85] Shapiro E. The Family of Concurrent Logic Programming Languages. ACM Computing Surveys, vol.21, pages 413-510, 1989. [86] Shipman D. The Functional Data Model and the Data Language DAPLEX. ACM Transactions on Database Systems, vol.6, n.1, pages 140-173, March 1981. [87] Shlaer S., Mellor S.J. Object Lifecycles: Modeling the Worl in States. Yourdon Press/Prentice Hall, 1992. [88] Siddiqi J. Challenging Universal Truths of Requirements Engineering. IEEE Software, pages 18-19, March 1994. BIBLIOGRAFÍA 217 [89] Siddiqi J., Morrey I.C., Roast C.R., Ozcan M.B. Towards Quality Requirements via Animated Formal Specifications. Annals of Software Engineering, Vol.3, pages 131-155, 1997. [90] Somé S., Dssouli R., Vaucher J. Towards an Automation of Requirements Engineering using Scenarios. Journal of Computing and Information, vol.2, n.1, pages 1110-1132, 1996. [91] Sommerville I. Software Engineering. Addison-Wesley, 1995. [92] Teorey T., Yang D., Fry J. A Logical Design Methodology for Relational Databases using the Extended Entity-Relationship Model. Computing Surveys, vol.18, n.2, pages 197-222, Junio 1988. [93] Torres J. Especificaciones Orientadas a Objetos Basadas en Restricciones: Prototipado Basado en un Lenguaje Orientado a Procesos. Tesis Doctoral, Depto. Lenguajes y Sistemas Informáticos, Universidad de Sevilla. 1997. [94] Proyect 2RARE: 2 Real Applications for Requirements Engineering. Deliverable D12: “Final Rreport on User’s Results” and Deliverable 13: “Final Report on Supplier’s Results”, 1996, http://www.info.fundp.ac.be/~phe/2rare.html. [95] Ueda K. Guarded Horn Clauses. Technical Report TR-103, ICOT, 1985. [96] Wieringa R.J. A Conceptual Model Specification Language (CMSL Version 2). Technical Report IR-248, Departament of Mathematics and Computer Science, Vrije Universiteit, The Netherlands, May 1992. [97] Wieringa R.J., Meyer J.-J.Ch. Actors, Actions and Initiative in Normative System Specification. Annals of Mathematics and Artificial Intelligence, vol.7, pages 289-346, 1993. [98] Wieringa R.J. Requirements Engineering: Frameworks for understanding. John Wiley & Sons, 1996. [99] Wing J.M. A Specifier’s Introduction to Formal Methods. IEEE Computer, vol.23, num.9, pages 8-24, September 1990. [100] Yoshida K., Chikayama T. A’UM: A String Based Concurrent ObjectOriented Language. In Proceedings of the International Conference on Fifth Generation Computer Systems, Institute for New Generation Computer Systems (ICOT), pages 638-649, Tokio, December 1988. [101] Yourdon E. Modern Structured Analysis. Yourdon Press/Prentice Hall, 1989. Índice alfabético control, 41 en OASIS 2.2, 69 repetición, 32 acción, 63 conflicto, 65 conjunto consistente, 25 definición, 24 efecto, 25 obligatoria, 26 ocurrencia, 25 permitida, 26 action calling, 78 action sharing, 79 ACTORS, 89 ALBERT, 10, 21 animación, 13 arquitecturas software, 80 escenarios, 9, 20 estado de violación, 27 eventos compartidos, 70 everyone, 37 guardas profundas, 126 ingeniería de requisitos, 7 LCM, 10 mecanismo de comunicación action calling, 78 action sending, 76 action sharing, 79 action waiting, 77 MENHIR, 2, 140 modelo de ejecución, 92 algoritmo, 102 ejemplo, 103 mundo, 29 buzón, 94 call/return, 80 cambio de estado, 25 ciclo de vida del objeto, 24 cliente, 24, 36, 38, 64 comunicación acción, 75 asíncrono, 76 ocurrencia forzada, 76 ocurrencia no forzada, 76 síncrono, 76 concurrencia, 64 intra-objeto, 95 CREWS, 9 objeto atributo, 24, 25 atributo evaluado, 25 estado del, 25 evento, 24 mecanismo de identificación, 35 oid, 35 vida o traza del, 26 obligación, 29 diagrama de vida del objeto, 33, 42, 44, 95, 103 disparos 218 ÍNDICE ALFABÉTICO OBLOG, 10, 19, 20, 145 OO-METHOD, 10, 19, 21 operación, 26, 63 acción de inicio, 64 acción de término, 64 operación, 24, 49 paso, 26, 63 permiso, 29 perspectiva cliente, 31, 39 proceso, 26 en Lógica Dinámica, 54 en OASIS 2.2, 48 en OASIS 3.0, 49 estado del, 51 grafo de transición, 51 paso, 63 procesos anidados, 65 procesos perpetuos, 125 programación automática, 14 prohibición, 29 protocolo, 24, 26, 49 relación afecta, 96 repositorio, 139, 173 self, 37, 99 semántica, 28 fórmulas de obligación, 29 fórmulas de permiso, 29 transición válida, 28 servicio, 24 servidor, 24, 36, 38, 63 someone, 37 TESORO, 10, 20, 21 timeout, 78 traductor OASIS-KL1, 141 transacción, 50 transición válida, 29 TROLL, 10, 21, 69, 72, 73 UML, 9, 10, 16, 173 219 verificación y validación, 11