EL PARADIGMA DE LA ORIENTACION A OBJETO EN SQL:1999 Y

Anuncio
El Paradigma de la Orientación
a Objeto en SQL:1999
y Oracle 8i
Capacidades y Limitaciones
Universidad Del Bío-Bío
Facultad de Ciencias Empresariales
Depto. de Auditoría e Informática
Ingeniería de Ejecución en Computación e Informática
El Paradigma de la Orientación
a Objeto en SQL:1999
y Oracle 8i
Capacidades y Limitaciones
Informe para optar al título profesional de
Ingeniero de Ejecución
en Computación e Informática
Alumno
Miguel Esteban Romero Vásquez.
Profesor Guía
Gilberto Gutiérrez Retamal.
Chillán, diciembre del 2001
“Los buenos viven eternamente;
El Altísimo cuida de ellos.
Por lo tanto recibirán de manos
del Señor un reino glorioso y
una hermosa corona; ...”
( Sabiduría 5, 15-17)
A la Memoria de Rodrigo Muñoz
(1977-1997)
Y dedicado a Mis Padres.
Resumen del Contenido General
Resumen del Contenido General ..............................................................iv
Contenido General ...................................................................................vi
Resumen
.............................................................................................xiv
Agradecimientos .....................................................................................xv
1 Introducción.......................................................................................... 1
2 El Paradigma de la Orientación a Objeto................................................ 3
2.1 Introducción ............................................................................................................. 4
2.2 Conceptos Básicos.................................................................................................... 6
3 Bases de datos Orientadas a Objeto .................................................... 22
3.1 Introducción ........................................................................................................... 23
3.2 Estándares de SABDOO ........................................................................................... 27
4 La Orientación a Objeto en SQL:1999 .................................................. 34
4.1 Introducción ........................................................................................................... 35
4.2 Soporte a la Orientación a objeto ............................................................................ 40
4.3 Evaluación .............................................................................................................. 83
5 Oracle 8i y la Orientación a Objeto. ..................................................... 87
5.1 Introducción ........................................................................................................... 88
5.2 Soporte a la Orientación a Objeto ........................................................................... 89
5.3 Evaluación ............................................................................................................ 134
6 Una Aplicación de ejemplo ................................................................ 138
6.1 Introducción ......................................................................................................... 139
6.2 Descripción del Prototipo...................................................................................... 146
6.3 Diseño del prototipo............................................................................................. 154
7 Conclusiones .................................................................................... 169
Apéndice A: Sintaxis de SQL:1999 Relacionada con la OO. ................... 172
A.1 Leyenda ............................................................................................................... 173
A.2 Sentencias............................................................................................................ 174
Apéndice B: UML .................................................................................. 190
B.1 ¿Qué es UML?........................................................................................................ 191
Apéndice C: Código Fuente del Prototipo y Pantallas ........................... 201
C.1 Creación de tipos ................................................................................................. 202
C.2 Definición de Tablas de objetos e inserción de instancias ..................................... 239
C.3 Pantallas. ............................................................................................................. 245
C.4 Código Java. ......................................................................................................... 254
Bibliografía........................................................................................... 375
Contenido General
Resumen del Contenido General ..............................................................iv
Contenido General ...................................................................................vi
Resumen
.............................................................................................xiv
Agradecimientos .....................................................................................xv
1 Introducción.......................................................................................... 1
2 El Paradigma de la Orientación a Objeto................................................ 3
2.1 Introducción ............................................................................................................. 4
2.1.1 ¿Qué es el paradigma de la orientación a objeto?............................................. 4
2.2 Conceptos Básicos.................................................................................................... 6
2.2.1 Objetos ........................................................................................................... 6
2.2.1.1 Estado....................................................................................................... 7
2.2.1.2 Comportamiento y Mensajes ..................................................................... 8
2.2.1.3 Identidad .................................................................................................. 9
2.2.2 Abstracción y Clase. ........................................................................................ 9
2.2.3 Encapsulamiento ........................................................................................... 11
2.2.4 Modularidad.................................................................................................. 11
2.2.5 Jerarquía de Clases........................................................................................ 12
2.2.5.1 Herencia ................................................................................................. 13
2.2.5.1.1 Polimorfismo .................................................................................... 15
2.2.5.2 Asociación .............................................................................................. 16
2.2.5.3 Agregación y Composición ...................................................................... 17
2.2.6 Tipos (tipificación)......................................................................................... 17
2.2.7 Concurrencia................................................................................................. 18
2.2.8 Persistencia................................................................................................... 19
2.2.8.1 Formas de solucionar el problema de la persistencia ............................... 19
2.2.8.1.1 Archivos convencionales ................................................................... 19
2.2.8.1.2 Bases de datos relacionales ............................................................... 20
2.2.8.1.3 Bases de datos orientadas a objetos.................................................. 20
3 Bases de datos Orientadas a Objeto .................................................... 22
3.1 Introducción ........................................................................................................... 23
3.1.1 Bases de datos relacionales ........................................................................... 23
3.1.2 Bases de datos orientadas a objeto................................................................ 24
3.1.2.1 Nuevos requerimientos ........................................................................... 24
3.2 Estándares de SABDOO ........................................................................................... 27
vi
Contenido General
3.2.1 Las tendencias: SABD relacionales “Extendidos” vs. SABDOO “Puros” .............. 27
3.2.2 Estándar SQL:1999 ........................................................................................ 30
3.2.2.1 Origen y evolución .................................................................................. 30
3.2.2.2 Partes que lo componen .......................................................................... 31
3.2.3 Estándar ODMG 2.0 ....................................................................................... 32
3.2.3.1 Origen y evolución .................................................................................. 32
3.2.3.2 Partes que lo componen .......................................................................... 32
4 La Orientación a Objeto en SQL:1999 .................................................. 34
4.1 Introducción ........................................................................................................... 35
4.1.1 Organizaciones preocupadas de la estandarización de SQL........................... 35
4.1.2 Nuevas características. .................................................................................. 37
4.1.2.1 Nuevos Tipos de Datos............................................................................ 37
4.1.2.2 nuevos predicados .................................................................................. 38
4.1.2.3 semántica reforzada................................................................................ 38
4.1.2.4 seguridad adicional ................................................................................. 39
4.1.2.5 bases de datos activa .............................................................................. 39
4.2 Soporte a la Orientación a objeto ............................................................................ 40
4.2.1 Tipos, abstracción y clases ............................................................................ 40
4.2.1.1 Creación de tipos (CREATE TYPE) ............................................................. 40
4.2.1.2 Atributos................................................................................................. 42
4.2.1.3 Métodos.................................................................................................. 43
4.2.1.3.1 Métodos de Instancia ........................................................................ 44
4.2.1.3.2 Métodos estático............................................................................... 47
4.2.1.3.3 Constructores ................................................................................... 48
4.2.1.3.4 Creación de métodos (CREATE METHOD) ........................................... 48
4.2.1.4 Modificación de tipos (ALTER TYPE) ......................................................... 52
4.2.1.4.1 Agregar un atributo .......................................................................... 52
4.2.1.4.2 Eliminar un atributo .......................................................................... 53
4.2.1.4.3 Agregar un método........................................................................... 53
4.2.1.4.4 Eliminar un método........................................................................... 54
4.2.1.5 Eliminación de tipos (DROP TYPE) ............................................................ 54
4.2.1.6 Comparación de instancias...................................................................... 55
4.2.1.6.1 Eliminación de funciones de comparación ......................................... 57
4.2.1.7 Conversión de UDT (CAST definidos por el usuario) ................................. 58
4.2.1.7.1 Eliminación de CAST definidos por el usuario .................................... 59
4.2.2 Colecciones................................................................................................... 59
4.2.2.1 Arreglos.................................................................................................. 59
4.2.3 Encapsulamiento ........................................................................................... 60
4.2.4 Modularidad.................................................................................................. 62
4.2.5 Persistencia................................................................................................... 62
vii
Contenido General
4.2.5.1 Manejo de Tablas .................................................................................... 62
4.2.5.1.1 Creación (CREATE TABLE) .................................................................. 62
4.2.5.1.2 Modificación (ALTER TABLE) .............................................................. 65
4.2.5.1.3 Eliminación (DROP TABLE) ................................................................. 66
4.2.5.2 Manejo de Instancias............................................................................... 67
4.2.5.2.1 Inserción de objetos.......................................................................... 67
4.2.5.2.2 Selección de objetos (SELECT) ........................................................... 69
4.2.5.2.3 Modificación de objetos .................................................................... 71
4.2.5.2.4 Eliminación de objetos ...................................................................... 72
4.2.6 Jerarquía de Clases........................................................................................ 73
4.2.6.1 Asociación .............................................................................................. 73
4.2.6.2 Agregación y Composición ...................................................................... 75
4.2.6.3 Herencia y Polimorfismo.......................................................................... 76
4.2.7 Concurrencia................................................................................................. 78
4.2.8 Manejo de Versiones de objetos y configuraciones ........................................ 79
4.2.9 Evolución de esquemas y de Instancias.......................................................... 79
4.2.10 Transacciones y recuperación ante fallos ..................................................... 80
4.2.11 Mecanismos de Autorización ....................................................................... 80
4.2.12 Compatibilidad con el modelo relacional ..................................................... 80
4.2.13 Limitaciones encontradas en SQL:1999........................................................ 82
4.3 Evaluación .............................................................................................................. 83
4.3.1 Criterios de evaluación .................................................................................. 83
4.3.2 Matriz de evaluación ..................................................................................... 85
5 Oracle 8i y la Orientación a Objeto. ..................................................... 87
5.1 Introducción ........................................................................................................... 88
5.2 Soporte a la Orientación a Objeto ........................................................................... 89
5.2.1 Tipos, abstracción y clases ............................................................................ 89
5.2.1.1 Estructura de un tipo objeto .................................................................... 90
5.2.1.2 Sintaxis para la creación de tipos ............................................................ 90
5.2.1.2.1 CREATE TYPE .................................................................................... 91
5.2.1.2.2 CREATE TYPE BODY ........................................................................... 94
5.2.1.3 Atributos................................................................................................. 95
5.2.1.4 Métodos.................................................................................................. 99
5.2.1.4.1 Constructor ...................................................................................... 99
5.2.1.4.2 Miembro (member) ......................................................................... 100
5.2.1.4.3 Estático (Static) ............................................................................... 102
5.2.1.4.4 Comparación (Map u Order) ............................................................ 102
5.2.1.4.5 Sobrecarga de métodos................................................................... 104
5.2.1.5 Alternativas para la implementación de los métodos ............................. 105
5.2.1.5.1 Implementación de los métodos con PL/SQL ................................... 106
viii
Contenido General
5.2.1.5.2 Implementación de métodos con JAVA ............................................ 106
5.2.1.5.3 Implementación de métodos con C ................................................. 109
5.2.1.6 Modificación de tipos (ALTER TYPE) ....................................................... 110
5.2.1.7 Eliminación de tipos (DROP TYPE y DROP TYPE BODY) ............................ 112
5.2.2 Tipo Colección ............................................................................................ 112
5.2.2.1 Métodos de un tipo colección................................................................ 113
5.2.2.2 VARRAY ................................................................................................ 114
5.2.2.3 Tablas anidadas .................................................................................... 116
5.2.3 Encapsulamiento ......................................................................................... 117
5.2.4 Modularidad................................................................................................ 118
5.2.5 Persistencia................................................................................................. 118
5.2.5.1 Manejo de tablas (relacionales y de objetos) .......................................... 118
5.2.5.1.1 Creación (Create Table) ................................................................... 118
5.2.5.1.2 Modificación (Alter Table)................................................................ 121
5.2.5.1.3 Eliminación (Drop Table) ................................................................. 121
5.2.5.2 Manejo de objetos................................................................................. 122
5.2.5.2.1 Inserción de objetos (INSERT INTO) ................................................. 122
5.2.5.2.2 Selección de objetos (SELECT ... FROM)............................................ 124
5.2.5.2.3 Modificación de objetos (UPDATE) ................................................... 125
5.2.5.2.4 Eliminación de objetos (DELETE) ...................................................... 126
5.2.6 Jerarquía de Clases...................................................................................... 126
5.2.6.1 Asociación ............................................................................................ 126
5.2.6.2 Agregación y Composición .................................................................... 127
5.2.6.3 Herencia y Polimorfismo........................................................................ 128
5.2.7 Concurrencia............................................................................................... 129
5.2.8 Manejo de Versiones de objetos y Configuraciones...................................... 129
5.2.9 Evolución de esquemas y de Instancias........................................................ 130
5.2.10 Transacciones y recuperación ante fallos. .................................................. 130
5.2.11 Mecanismos de autorización ..................................................................... 131
5.2.12 Compatibilidad con el modelo relacional ................................................... 131
5.2.13 Limitaciones encontradas en Oracle 8i....................................................... 132
5.3 Evaluación ............................................................................................................ 134
5.3.1 Criterios de evaluación ................................................................................ 134
5.3.2 Matriz de evaluación ................................................................................... 136
6 Una Aplicación de ejemplo ................................................................ 138
6.1 Introducción ......................................................................................................... 139
6.1.1 Importancia del recurso hídrico [29] ............................................................ 139
6.1.2 Gestión del recurso hídrico en Chile ............................................................ 140
6.1.3 Modelación de cuencas y proceso de Simulación hidrológico operacional. ... 141
6.1.3.1 Simulación ............................................................................................ 145
ix
Contenido General
6.2 Descripción del Prototipo...................................................................................... 146
6.2.1 Descripción de los objetos soportados ........................................................ 147
6.2.1.1 Nodos. .................................................................................................. 147
6.2.1.2 Ríos y tramos de río. ............................................................................. 148
6.2.1.3 Embalses. ............................................................................................. 149
6.2.1.4 Central Hidroeléctrica de pasada ........................................................... 150
6.2.1.5 Canal Principal ...................................................................................... 151
6.2.1.6 Hoya Intermedia.................................................................................... 152
6.2.1.7 Régimen Natural ................................................................................... 152
6.2.1.8 Captación de Agua Potable.................................................................... 153
6.3 Diseño del prototipo............................................................................................. 154
6.3.1 Diagramas de clases.................................................................................... 154
6.3.1.1 Clases implementadas en Oracle 8i ....................................................... 154
6.3.1.2 Clases implementadas en Java............................................................... 161
6.3.2 Diagramas de colaboración ......................................................................... 166
6.3.2.1 Simulación ............................................................................................ 166
6.3.3 Limitaciones Encontradas ............................................................................ 168
6.3.3.1 Limitaciones de PL/SQL ......................................................................... 168
6.3.3.2 Limitaciones de Oracle y la exportación de tipos ................................... 168
7 Conclusiones .................................................................................... 169
Apéndice A: Sintaxis de SQL:1999 Relacionada con la OO. ................... 172
A.1 Leyenda ............................................................................................................... 173
A.2 Sentencias............................................................................................................ 174
A.2.1 Creación de tipos (CREATE TYPE)................................................................. 174
A.2.2 Definición de atributos................................................................................ 176
A.2.3 Modificación de tipos (ALTER TYPE) ............................................................. 176
A.2.4 Creación de métodos, funciones y procedimientos ...................................... 177
A.2.5 Modificación de métodos, funciones y procedimientos ................................ 179
A.2.6 CAST definido por el usuario ....................................................................... 180
A.2.7 Eliminación de un CAST............................................................................... 181
A.2.8 Definición del ORDERING de un tipo. ........................................................... 181
A.2.9 Eliminación de un user definer ordering ...................................................... 182
A.2.10 Funciones de transformación de tipos ....................................................... 182
A.2.11 Eliminación de funciones de transformación.............................................. 183
A.2.12 Definición de Tablas (CREATE TABLE) ........................................................ 183
A.2.13 Modificación de tablas (ALTER TABLE)........................................................ 186
A.2.14 Eliminación de tablas (DROP TABLE) .......................................................... 187
A.2.15 Inserción de filas (INSERT INTO) ................................................................ 187
A.2.16 Actualización de filas (UPDATE) ................................................................. 188
A.2.17 Eliminación de filas (DELETE FROM) ........................................................... 188
x
Contenido General
Apéndice B: UML .................................................................................. 190
B.1 ¿Qué es UML?........................................................................................................ 191
B.1.1 Diagramas de clases .................................................................................... 193
B.1.1.1 Compartimentos adicionales ................................................................. 194
B.1.1.2 Estereotipos .......................................................................................... 195
B.1.1.3 Asociaciones ......................................................................................... 196
B.1.1.4 Agregación y composición..................................................................... 196
B.1.1.5 Generalización ...................................................................................... 197
B.1.1.6 Restricciones y comentarios .................................................................. 198
B.1.2 Diagrama de colaboración ........................................................................... 199
B.1.3 Para Más información. ................................................................................. 200
Apéndice C: Código Fuente del Prototipo y Pantallas ........................... 201
C.1 Creación de tipos ................................................................................................. 202
C.1.1 array_caudal. .............................................................................................. 202
C.1.2 arr_caudales................................................................................................ 202
C.1.3 Punto .......................................................................................................... 204
C.1.4 arr_puntos .................................................................................................. 204
C.1.5 Polilinea ...................................................................................................... 204
C.1.6 Cuadrado .................................................................................................... 207
C.1.7 Elipse.......................................................................................................... 207
C.1.8 Triangulo .................................................................................................... 208
C.1.9 Graf_flujo.................................................................................................... 209
C.1.10 graf_cent_hidro ......................................................................................... 209
C.1.11 graf_nodo ................................................................................................. 210
C.1.12 graf_emb .................................................................................................. 210
C.1.13 graf_Cuenca.............................................................................................. 210
C.1.14 Cuenca ..................................................................................................... 211
C.1.15 Nodo......................................................................................................... 213
C.1.16 Rio............................................................................................................ 217
C.1.17 Hoya_inter ................................................................................................ 217
C.1.18 Regimen_Natural....................................................................................... 219
C.1.19 Salida_Emb................................................................................................ 220
C.1.20 Aportante.................................................................................................. 221
C.1.21 Canal ........................................................................................................ 222
C.1.22 Tramo....................................................................................................... 224
C.1.23 Central_hidro ............................................................................................ 226
C.1.24 Apor_extrac .............................................................................................. 228
C.1.25 Cap_agua_Pot ........................................................................................... 230
C.1.26 Extracción................................................................................................. 231
C.1.27 Flujo ......................................................................................................... 233
xi
Contenido General
C.1.28 Embalse .................................................................................................... 235
C.2 Definición de Tablas de objetos e inserción de instancias ..................................... 239
C.2.1 Tabla: tbl_cuenca ..................................................................................... 239
C.2.2 Tabla: tbl_nodo ........................................................................................ 239
C.2.3 Tabla: tbl_rio .......................................................................................... 239
C.2.4 Tabla: tbl_Flujo ...................................................................................... 239
C.2.5 Tabla: tbl_Emb .......................................................................................... 239
C.2.6 Inserción de una Cuenca ............................................................................. 240
C.2.7 Inserción de un Rio ..................................................................................... 240
C.2.8 Inserción de un Nodo .................................................................................. 240
C.2.9 Inserción de un Embalse y sus salidas ......................................................... 240
C.2.10 Inserción de un Regimen Natural............................................................... 242
C.2.11 Inserción de una Hoya Intermedia ............................................................. 242
C.2.12 Inserción de una Captación de Agua Potable ............................................. 243
C.2.13 Inserción de una Central Hidroeléctrica ..................................................... 243
C.2.14 Inserción de un Tramo de Rio.................................................................... 243
C.2.15 Inserción de un Canal................................................................................ 244
C.3 Pantallas. ............................................................................................................. 245
C.3.1 Datos de Conexión...................................................................................... 245
C.3.2 Abrir cuenca existente ................................................................................ 245
C.3.3 Ventana Principal, después de abrir una cuenca. (Frame1.java) .................... 246
C.3.4 Agregar Cuenca .......................................................................................... 246
C.3.5 Ventana simulación al finalizar.................................................................... 247
C.3.6 Nodos y sus caudales .................................................................................. 247
C.3.7 Modificando un Rio (FrmModificarRio.java y FrmRio.java)............................. 248
C.3.8 Acerca de (Frame1_AboutBox.java) .............................................................. 248
C.3.9 Propiedadas de un Canal (FrmCanal.java) .................................................... 249
C.3.10 Propiedades de una Captación de Agua Potable (FrmCapAguaPot.java) ...... 249
C.3.11 Propiedades de una central hidroeléctrica (FrmCentralHidro.java) .............. 249
C.3.12 Propiedades de una hoya intermedia (frmHoyaInter.java) ........................... 250
C.3.13 Propiedades de un régimen natural (frmRegNat.java)................................. 250
C.3.14 Propiedades de una salida de embalse (frmSalidaEmb.java) ....................... 250
C.3.15 Propiedades de un tramo de río (FrmTramo.java)....................................... 251
C.3.16 Propiedades de un nodo (frmNodo.java) .................................................... 251
C.3.17 Ventana para la modificación del Zoom (FrmZoom.java) ............................ 251
C.3.18 Menu Cuenca ............................................................................................ 252
C.3.19 Menu Río .................................................................................................. 252
C.3.20 Menu Zoom............................................................................................... 252
C.3.21 Menu Insertar............................................................................................ 252
C.3.22 Menu Consultas ........................................................................................ 253
xii
Contenido General
C.3.23 Menu Ayuda.............................................................................................. 253
C.4 Código Java. ......................................................................................................... 254
C.4.1 Paquete consultorSql................................................................................... 254
C.4.1.1 Clase: ConectorJDBC ............................................................................... 254
C.4.1.2 Clase: FrmConexion ................................................................................ 257
C.4.1.3 Clase: FrmConsultor .............................................................................. 265
C.4.1.4 Clase: JDBCAdapter ................................................................................ 268
C.4.1.5 Clase: OldJTable..................................................................................... 273
C.4.1.6 Clase sqlQuery....................................................................................... 277
C.4.1.7 Clase: TableMap ...................................................................................... 281
C.4.1.8 Clase: TableSorter................................................................................. 282
C.4.2 Paquete cuencamaule.................................................................................. 289
C.4.2.1 Clase: Frame1 ........................................................................................ 289
C.4.2.20 Clase: MainGui..................................................................................... 313
C.4.3 Paquete Figuras .......................................................................................... 314
C.4.3.1 Clase: Cuadrilatero ............................................................................. 314
C.4.3.2 Clase: Dibujante.................................................................................... 316
C.4.3.3 Clase: Elipse ........................................................................................ 321
C.4.3.4 Clase: FigGeo ........................................................................................ 323
C.4.3.5 Interfaz: Graficable ............................................................................. 323
C.4.3.6 Clase: LienzoCuenca ............................................................................. 324
C.4.3.7 Clase: Poligono..................................................................................... 327
C.4.3.8 Clase: PoliLinea................................................................................... 329
C.4.3.9 Clase: Punto .......................................................................................... 333
C.4.3.10 Clase: Triangulo................................................................................. 334
C.4.4 Paquete objcuenca ...................................................................................... 337
C.4.4.1 Clase: AporExtracOra ........................................................................... 338
C.4.4.2 Clase: AporExtracOraRef...................................................................... 346
C.4.4.3 Clase: BDObjCuenca ............................................................................... 348
C.4.4.4 Clase: GuiEmbalse ................................................................................. 353
C.4.4.5 Clase: GuiFlujo..................................................................................... 358
C.4.4.6 Clase: GuiNodo....................................................................................... 371
Bibliografía........................................................................................... 375
xiii
Resumen
Cuando desarrollamos aplicaciones bajo el paradigma de la orientación a
objeto, nos encontramos con el problema de la persistencia. Para solucionar
esto, existen diversas estrategias pasando por simples archivos, hasta bases
de datos orientadas a objetos.
Las bases de datos relacionales hasta el
estándar SQL-92 no daban soporte al almacenamiento de objetos, pero, la
actual versión aprobada, del estándar llamada SQL:1999, da soporte a dichas
características.
El presente trabajo tuvo como objetivo general analizar las capacidades y
limitaciones del estándar SQL:1999 y del SABD Oracle 8i, para dar soporte al
paradigma de la orientación a objeto.
En una primera etapa, describimos los conceptos básicos del paradigma de la
orientación a objeto y las características y los tipos de bases de datos
orientadas a objeto junto con sus estándares respectivos.
Después,
analizamos y describimos detalladamente cómo el estándar SQL:1999
implementa la orientación a objeto, y evaluamos dicha implementación. Lo
mismo hicimos con el SABD Oracle 8i.
Finalmente, implementamos un prototipo, utilizando como lenguaje a Java y
como SABD a Oracle 8i, con el objetivo de evaluar empíricamente la
implementación del paradigma de la orientación a objeto en Oracle8i.
Como resultado de este trabajo, podemos decir que el estándar SQL:1999
implementa en un 78,25% el paradigma de la orientación a objeto, mientras
que el SABD Oracle 8i lo implementa en un 70,58%.
La limitación más
importante que tiene el SABD Oracle 8i frente a SQL:1999 es la falta de
herencia y el deficiente soporte a la evolución de esquemas.
El estándar SQL:1999, es lo suficientemente robusto para dar soporte a la
persistencia de los objetos, a diferencia del SABD Oracle 8i debido a su falta
de herencia.
xiv
Agradecimientos
Si hay algo que me ha costado hacer, es el trabajo que hoy estás leyendo.
Dos años de sacrificios, que hubieran sido eternos y quizás un rotundo
fracaso, sin la ayuda de muchos. En primer lugar quiero dar gracias a Dios,
por llenarme de bendiciones todos los días, quien me dio todos mis talentos
y es la luz en mi camino. A mis padres, Miguel y Patricia, que me han sabido
enseñar, acompañar y amar, dándome todo su apoyo y comprensión,
“tirándome las orejas” cuando me lo merecía y buscando siempre lo mejor
para mi. Junto con ellos a mis hermanos, Fabián y Pablo, por soportar mi mal
humor durante el desarrollo del proyecto. A mis amigos y compañeros de
universidad, JUFRA, Hogar de Cristo, AUC, RCC, Peñihuén Juvenil y a mis
amigos que han partido: Gonzalo Seguel, Rodrigo Fuentes y Rodrigo Muñoz
por toda la amistad y los buenos momentos que pasamos juntos.
A mis
profesores, en especial a los que me acompañaron en la universidad por su
apoyo, consejo y educación.
A la profesora María Antonieta, por su tiempo
y apoyo en lo referente a UML. A mi profesor guía Gilberto Gutiérrez, por su
apoyo, guía y comprensión a lo largo de todo el proyecto. Al Ministerio de
Obras Públicas (MOP), pero en particular a Mauricio Zambrano, por su tiempo
y apoyo en la explicación de los modelos de simulación hidrológica, y por las
revisiones hechas al prototipo. A Marlene Sáez por su ayuda en la traducción
del estándar SQL-1999. Y a todos los que de una u otra manera han estado
conmigo...
...Muchas Gracias.
Miguel Esteban Romero Vásquez.
Paz y Bien a todos
xv
1 Introducción
La orientación a objeto, desde sus orígenes ha sido un paradigma muy
prometedor para el desarrollo de software. En estos últimos años, hemos
visto aparecer varios productos, estándares y herramientas que han marcado
un hito en la historia de la Orientación a Objeto. Uno de ellos es el lenguaje
Java que da un soporte muy completo al paradigma de la orientación a
objeto, además, de contar con características que facilitan el desarrollo de
programas (fácil de aprender, multiplataforma, multihilo, cliente/servidor,
robusto, seguro, etc). Otro hito importante lo ha marcado la notación UML,
que rápidamente se ha convertido en el estándar para el desarrollo orientado
a objeto (ver apéndice B).
A partir de UML, se han desarrollado varias
herramientas CASE, por ejemplo: Rational Rose de Rational Software y
Object Database Designer (ODD) de Oracle. Rational Rose permite diseñar
sistemas utilizando la notación UML y a partir de estos diseños, generar
automáticamente los programas en distintos lenguajes orientados a objeto,
como por ejemplo en Java y en C++. Mediante ODD podemos diseñar las
bases de datos y los tipos objetos que utilizaremos en Oracle, luego serán
generadas automáticamente las estructuras en el SABD.
Otra área del desarrollo del paradigma, son las bases de datos orientadas a
objeto. Las cuales nacen para solucionar el problema de la persistencia de
los objetos, en forma eficiente.
En esta área existen dos líneas de
investigación y desarrollo, cada una con su respectivo estándar.
El tema
central de este trabajo corresponde a una de las líneas de investigación,
definida por el estándar SQL:1999.
Los objetivos de este trabajo son:
Objetivo general:
Analizar las capacidades y limitaciones del estándar SQL:1999 y del
SABD Oracle 8i, para dar soporte al paradigma de la orientación a
objeto.
Objetivos específicos:
1. Analizar las capacidades y limitaciones del modelo objeto
considerado por SQL:1999.
Introducción
2. Analizar las capacidades y limitaciones del modelo objeto en el
SABD Oracle 8i.
3. Verificar las capacidades mediante la implementación de un
prototipo
Al iniciar este proyecto, el estándar SQL:1999 no había sido aprobado, y era
conocido como SQL-3.
A esas alturas, ya existían productos que daban
soporte a la orientación a objeto basándose en el borrador de trabajo, entre
ellos Oracle 8i.
Ahora que el estándar está aprobado, es de esperar que
aparezcan productos que implementen dicha especificación, pero por el
momento tendremos que conformarnos con implementaciones incompletas
basadas en el borrador de trabajo de SQL.
En el capítulo uno de este trabajo, explicaremos las características
fundamentales del paradigma de la orientación a objeto, y plantearemos el
problema de la persistencia, que es lo que solucionan las bases de datos
orientadas a objeto. En el dos, haremos una breve reseña histórica de las
bases de datos. Explicaremos las dos líneas de desarrollo en este campo y
sus estándares.
En el tres, describiremos detalladamente todas las
características de la orientación a objeto manejadas por SQL:1999. El orden
en que describimos los conceptos es el mismo en el que explicamos las
características del paradigma de la orientación a objeto en el capítulo 1. Al
final del capítulo haremos una evaluación del soporte de la orientación a
objeto en SQL:1999. En el capítulo 4, tendrá la misma estructura del capítulo
3,
para
facilitar
su
comparación
y
estudio.
Aquí
describiremos
detalladamente el manejo de objetos que hace Oracle 8i. Al final del capítulo
haremos una evaluación del soporte del paradigma de la orientación a objeto
que hace Oracle 8i.
En el capítulo cinco encontrará el desarrollo de una
aplicación orientada a objeto, utilizando el lenguaje Java y a Oracle 8i para
hacer persistir los objetos. La aplicación consiste en la implementación de un
modelo de simulación hidrológico operacional para una cuenca, realizando
una simulación de temporada.
Es necesario indicar que, por motivos de
tiempo, no existe una documentación bien detallada del diseño.
2
2 El Paradigma de la
Orientación a Objeto
2.1 Introducción
Las ideas de la orientación a objeto nacen a partir de los lenguajes de
programación orientados a objeto. El primero de ellos fue Simula, y desde
entonces se han desarrollado muchos
otros (Smalltalk, C++, Java, etc.).
Aprender estos lenguajes no es suficiente para desarrollar un software con
estas ideas, puesto que ellas forman un paradigma.
2.1.1 ¿Qué es el paradigma de la orientación a objeto?
Para poder responder a esta pregunta, analizaremos primero lo que significa
el vocablo paradigma.
Si buscamos el significado de esta palabra en un
diccionario, nos dirá que es un Ejemplo o Modelo, pero en el contexto
utilizado, es mucho más amplio.
El Historiador Tomas Kuhn define paradigma como un conjunto de teorías,
estándares y métodos que juntos representan una forma de organizar el
conocimiento, esto es, una forma de ver el mundo [5]. Todos los seres
humanos tenemos un conjunto de paradigmas que adquirimos a lo largo de
nuestra vida a través del aprendizaje y actuamos de acuerdo con ellos.
Nuestros paradigmas son de gran ayuda, porque nos permiten analizar
rápidamente la información que recibimos, además, nos dan una pauta de
cómo debemos actuar y reaccionar. Pero, cuando los hechos se escapan a la
regla general, nuestros paradigmas nos inducen a cometer errores o a tener
que reaccionar mucho más lento, para no cometerlos. Por ejemplo si vamos
conduciendo un automóvil, y el semáforo está en verde, simplemente
cruzamos la calle, puesto que el conocimiento que tenemos sobre el
semáforo, nos dice que podemos cruzar cuando la luz está de ese color, y
que por supuesto el otro lado tiene rojo. Pero ¿qué pasa si en realidad los
dos lados del semáforo están en verde?, lo más probable es que ocurra un
accidente. Que pasó aquí, bueno nuestros paradigmas nos jugaron una mala
pasada, tomamos una decisión rápida basada en ellos, sin percatarnos de
esta situación que escapa a la regla general.
4
El Paradigma de la orientación a objeto - Introducción
Al Programar un software tenemos varios paradigmas, que nos permiten
plantear soluciones. Algunos ejemplos de estos paradigmas son [4]:
•
Orientados a procedimientos (enfoque clásico)
•
Orientados a objetos
•
Orientados a Lógica
•
Orientados a Reglas
•
Orientados a Restricciones
Si ponemos atención a la definición de paradigma que plantea Tomas Kuhn,
nos daremos cuenta, que cada uno de estos ejemplos tiene su propia forma
de organizar el conocimiento y de mirar al mundo.
No existe el mejor paradigma, cada uno es más adecuado que el otro para
resolver cierto tipo de problemas. Por esta razón es necesario que sean
conocidos por los desarrolladores, sólo de este modo podrán escoger el
mejor, para su problema.
Los paradigmas que utilizamos para desarrollar un software abarcan más que
lo relacionado con la tarea de programar. Tomas Kuhn en su definición nos
plantea que son un conjunto de teorías, estándares y métodos, a partir de
ello, podríamos decir que un paradigma de desarrollo de software esta
compuesto por: modelos, métodos, y diagramas para realizar análisis,
diseño, programación, gestión del desarrollo y control de la calidad. Cada
uno de estos elementos está basado en un marco de referencia conceptual
propio del paradigma. En apoyo al desarrollo de software bajo un paradigma
en particular, tenemos herramientas, lenguajes de programación, y bases de
datos que, por supuesto, están acordes al marco conceptual del paradigma.
Entonces, el paradigma de la orientación a objeto, estaría compuesto por
todos los elementos antes descritos, donde el marco de referencia
conceptual, o toda la teoría en la que se basa, está orientada al objeto. Éste
marco de referencia conceptual en particular suele denominarse modelo de
objetos (por ejemplo en [4]).
La pregunta ahora es ¿qué es orientado a objeto?. En la siguiente sección se
responderá a esta pregunta.
5
2.2 Conceptos Básicos
En el Modelo Objeto existen cuatro elementos fundamentales, estos son:
Abstracción, Encapsulamiento, Modularidad y Jerarquía; donde “un
modelo que carezca de cualquiera de estos elementos no es orientado a
objetos” [4] página 45.
Y
tres
elementos
secundarios:
Tipos
(tipificación),
Concurrencia
y
Persistencia, donde “cada uno de ellos es una parte útil del modelo objeto
pero no es esencial.” [4] página 45.
Estos elementos parten de la noción de objeto, por ende definiremos primero
este concepto y luego, los elementos del modelo objeto.
2.2.1 Objetos
Los seres humanos estamos familiarizados con los objetos, los utilizamos
diariamente y desde muy temprana edad aprendemos a identificarlos y
reconocerlos [4]. Éstos pueden ser:
•
Una cosa Tangible y/o visible
•
Algo que puede comprenderse intelectualmente
•
Algo hacia lo que se dirige un pensamiento o acción.
Un objeto posee un conjunto de
características esenciales, llamadas
propiedades
o
atributos
[20].
Estos atributos son los que dan al
objeto su naturaleza o tipo y hacen
que el objeto no sea otro.
Por
ejemplo, un televisor tiene una
figura 1: Ejemplo de objetos
pantalla,
un
dispositivo
encendido y apagado, un selector de canales, una antena, etc.
televisor, no tuviera una
de
Si este
antena y un selector de canales, no sería un
televisor, sería un monitor de computador, que es otro tipo de objeto.
6
El Paradigma de la orientación a objeto – Conceptos Básicos
Además de las propiedades, un objeto tiene un conjunto de servicios,
operaciones o métodos [20], que definen el comportamiento del objeto, y
actúan sobre sus atributos. Siguiendo el ejemplo del televisor, podríamos
identificar los siguientes métodos:
Encender, Apagar, Cambiar Canal,
Sintonizar, Subir Volumen y Bajar Volumen.
Si realizamos una comparación entre la programación orientada a objetos y la
programación estructurada, podríamos decir que:
en la programación
orientada a objeto los atributos del objeto son como las variables y las
estructuras de datos; mientras que los métodos de los objetos serían como
las funciones o procedimientos que manipulan las estructuras de datos.
La
gran diferencia radica en que un objeto es una sola entidad compuesta por
atributos y métodos, en cambio en la programación estructurada, las
estructuras de datos y las funciones o procedimientos son cosas separadas.
Todo objeto tiene un estado, un comportamiento bien definido y una
identidad única [4]. Veamos qué significa cada concepto.
2.2.1.1 Estado
Las propiedades de los objetos suelen ser estáticas, es decir, no cambian en
el tiempo, aunque en algunos casos el objeto puede mutar y modificar su
conjunto de propiedades (evolución [2]).
Cada una de las propiedades de un objeto tiene algún valor y éste puede ser
una cantidad u otro objeto. El valor de un objeto es la parte dinámica de la
propiedad.
Las propiedades del objeto son los que definen su estado.
Grady Booch da
la siguiente definición de estado: “El Estado de un objeto abarca todas las
propiedades (normalmente estáticas) del mismo más los valores actuales
(normalmente dinámicos) de cada una de estas propiedades” [4] página 98.
7
El Paradigma de la orientación a objeto – Conceptos Básicos
Entonces, el estado de un objeto depende de los valores actuales de sus
atributos.
2.2.1.2 Comportamiento y Mensajes
El comportamiento de un objeto, representa su actividad visible y
comprobable exteriormente, y él está definido en sus métodos.
Los objetos se comportan de una manera conocida, esto permite que ellos
interactúen entre sí, colaborando en pos de un objetivo. Esta interacción se
logra a través del paso de mensajes, donde un mensaje es un mandato o
solicitud que un objeto envía a otro indicándole que debe realizar una acción,
lo que gatilla la ejecución de un método. Cada mensaje está compuesto por:
destino, operación y parámetros [20], donde el destino es el objeto
receptor, la operación es el método solicitado y los parámetros son el
conjunto de datos necesarios para ejecutar el método.
En la mayoría de los
lenguajes de programación orientados a objetos, un mensaje tiene la forma:
Destino.Operación(parámetro1, parámetro2, ... , parámetron).
Siguiendo
con el ejemplo del televisor, si tenemos un objeto llamado TV y quisiéramos
ver el canal 13, tendríamos que pasar los siguientes mensajes:
TV.encender()
TV.cambiarCanal(13)
Consideremos que el método encender(), sirve para prender y apagar el
televisor, de esta manera, el comportamiento del objeto al invocar este
método dependerá del estado actual del objeto, es decir, si él está encendido,
entonces se apagará, y viceversa. Además, este método, cambiará el estado
actual de encendido a apagado y viceversa.
Esto se produce porque el
comportamiento de un objeto altera el estado del mismo, y el estado actual
del objeto afecta su comportamiento.
Como resumen, veamos la siguiente definición
de Grady Booch: “el
comportamiento es como actúa y reacciona un objeto, en término de sus
cambios de estados y paso de mensajes” [4] página 98.
8
El Paradigma de la orientación a objeto – Conceptos Básicos
2.2.1.3 Identidad
La identidad es la característica del objeto que lo hace ser único y lo
distingue del resto de los objetos. Es importante destacar que la identidad
de un objeto es independiente de los valores actuales de sus atributos, por
ejemplo si tenemos un objeto libro, y cambiamos el valor del ISBN, éste va a
tener la misma identidad.
En los lenguajes de programación orientados al objeto, los objetos se
identifican con nombres de variables o a través de su OID (Object Identifier,
identificador de objeto) generados por el sistema. Un nombre de variable es
asignado por el programador, y el sistema se encarga de asociar ese nombre
con el OID correspondiente. Utilizando los OID, los objetos pueden compartir
otros objetos y se pueden crear redes entre ellos [2].
La Identidad de un Objeto hace que tengamos dos nociones de igualdad [2]:
•
Igualdad por identidad. Dos objetos son iguales si tienen el mismo
OID, es decir, son el mismo.
•
Igualdad por valor.
Dos objetos son iguales si los valores de sus
atributos son recursivamente iguales.
2.2.2 Abstracción y Clase.
La abstracción no sólo es utilizada en la orientación a objeto, ésta es una
capacidad humana que nos permite simplificar la realidad de manera que sea
más manejable. Ésta consiste en centrarnos en las características esenciales
de un objeto, descartando detalles que no son pertinentes en ese momento.
Una definición más formal sería : “Una abstracción denota las características
esenciales de un objeto que lo distinguen de todos los demás tipos de objetos
y proporciona así fronteras conceptuales nítidamente definidas respecto a la
perspectiva del observador.” [4] página 46.
En otras palabras, a través de una abstracción encontramos un conjunto de
atributos y métodos que son la esencia de un objeto, descartando los detalles
9
El Paradigma de la orientación a objeto – Conceptos Básicos
de su implementación por este momento.
Los atributos y métodos
identificados dependerán del dominio de la aplicación a desarrollar
(perspectiva del observador).
La manera en que representamos las abstracciones es a través de clases.
Una clase es la especificación de los atributos y métodos que debe tener un
objeto para pertenecer a esa clase, es decir es una abstracción del objeto. Al
leer esta definición, da la impresión que los términos son sinónimos, pero no
lo son. En algunos casos una abstracción será representada por una sola
clase, pero en otros, se necesitarán varias clases. Por ejemplo consideremos
la abstracción de un automóvil, con los atributos de: numPasajeros,
propietario,
numPuertas;
y
con
los
métodos:
avanzar(),
frenar(),
doblarIz(), doblarDer();
figura 2:Clase Automóvil
esta abstracción puede ser representada por una única clase como la
mostrada en la figura 2.
Por otro lado, si tratáramos de representar la
abstracción Industria, con los atributos: Empleados, departamentos,
muebles y útiles, maquinarias; y con los métodos: Comprar(), vender(),
fabricar(), inventariar(), balance(); difícilmente podríamos representarlo a
través de una sola clase.
Al incorporar el concepto de clase a la definición de objeto podemos decir
que: un objeto es una ocurrencia concreta (o instancia) de una clase, con una
identidad única, donde todos los objetos que comparten un mismo conjunto
de atributos y métodos están agrupados en una misma clase.
10
El Paradigma de la orientación a objeto – Conceptos Básicos
2.2.3 Encapsulamiento
El encapsulamiento es uno de los pilares fundamentales en que se basa la
orientación a objeto,
atributos
y
métodos
éste consiste en agrupar en una única entidad los
de
un
objeto,
ocultando
los
detalles
de
su
implementación. Para lograr esto, el objeto tiene dos partes, una pública o
visible
denominada
Interfaz
y
otra
privada
u
oculta
denominada
implementación. Al momento de definir la clase del objeto, se establece qué
atributos y métodos van a ser públicos, y cuáles privados. En el caso de los
métodos públicos, el algoritmo que utilizan para ejecutar el trabajo queda
oculto (forma parte de la implementación).
Con el concepto de encapsulamiento podemos decir que la abstracción de un
objeto corresponde a la interfaz de la clase encapsulada.
Cabe destacar que un encapsulamiento real se logra solamente cuando todos
sus atributos son privados, y la única forma de acceder a ellos, es a través de
métodos públicos [2].
Si un objeto permite que sus atributos sean públicos
pierde el control sobre los valores que le son asignados, no pudiendo realizar
la validación de los datos que se ingresan, pudiendo ser asignados valores
inválidos para esos atributos.
Un encapsulamiento real, hace que los métodos públicos sean como una
muralla que garantice la integridad y validez de los datos guardados por el
objeto en sus atributos. Además permite modificar la estructura interna del
objeto sin que estos cambios afecten a los que lo utilizan.
con los algoritmos implementados por los métodos.
Lo mismo pasa
Esto nos trae como
beneficio una facilidad de mantención, al minimizar los efectos colaterales
producidos por cambios en la implementación del objeto.
2.2.4 Modularidad
Como punto de partida tomaremos la definición de Booch que dice: “La
modularidad es la propiedad que tiene un sistema que ha sido descompuesto
en un conjunto de módulos cohesivos y débilmente acoplados.” [4] página 64.
11
El Paradigma de la orientación a objeto – Conceptos Básicos
Para entender esta definición debemos comprender el significado de módulo,
cohesión y acoplamiento desde la perspectiva de la orientación a objeto.
Un módulo es un conjunto de clases o abstracciones que han sido agrupadas
por guardar cierta relación lógica. El módulo pasa a ser un paquete que se
puede
diseñar,
encapsulamiento.
programar
Por
lo
y
compilar
general
los
separadamente,
módulos
no
son
gracias
al
totalmente
independientes, en la mayoría de los casos existen conexiones entre
módulos.
La cohesión se refiere al grado de relación lógica con el que se han agrupado
las clases. Mientras más tengan en común las clases, en función del objetivo
que persiguen, mayor es la cohesión.
Existen varios grados de cohesión,
siendo el más bajo la cohesión por coincidencia donde las clases son
agrupadas sin ninguna relación; y el más alto la cohesión funcional donde las
clases trabajan juntas para lograr un comportamiento bien delimitado [4].
El acoplamiento esta relacionado con el grado de dependencia que existen
entre un módulo y los demás. Lo que se busca es minimizar el acoplamiento,
para minimizar los efectos colaterales que pueda causar la modificación de
un módulo.
El Objetivo de la modularidad es hacer más manejable la programación a gran
escala, basándose en la estrategia “dividir para vencer”.
2.2.5 Jerarquía de Clases
Para modelar una determinada aplicación, no es suficiente definir todas las
clases que la componen, además de eso es necesario describir las relaciones
que existen entre ellas. Recordemos que todo sistema es un conjunto de
partes que interactúan entre sí.
Existen tres tipos básicos de relaciones entre clases [4]. La primera denota
una relación “Es un”, por ejemplo un automóvil es un medio de transporte. A
este tipo de relaciones se denomina herencia.
La segunda denota una
12
El Paradigma de la orientación a objeto – Conceptos Básicos
relación “parte de” por ejemplo un motor es parte de un automóvil. A este
tipo de relación se denomina agregación.
asociación,
Y por último tenemos la
que denota una relación semántica entre clases que de otro
modo no existiría. Un ejemplo de esto es la relación que se produce entre
una persona y un automóvil, cuando decimos que una persona es propietaria
de uno o más automóviles, o una persona conduce un automóvil.
El concepto de Jerarquía de clases también es uno de los pilares de la
orientación a objeto.
2.2.5.1 Herencia
La herencia permite definir una clase (llamada subclase) tomando como base
la definición de otra (llamada superclase).
La subclase hereda todos los
atributos y operaciones de la superclase, a lo que agrega sus propios
atributos y métodos [2]. Para construir este tipo de relaciones existen dos
procesos, uno llamado generalización y otro llamado especialización.
figura 3: Clases antes de la generalización
Por ejemplo, si hemos identificado las siguientes clases: automóvil, bicicleta,
camión (figura 3), podríamos extraer los atributos y operaciones que tienen
en común y con ellos generar una clase llamada medios_de_transporte
(figura 4) que pasaría a ser una superclase donde sus subclases automóvil,
bicicleta y camión tendrían sólo los atributos y métodos que no fueron
extraídos, puesto que ellos serán heredados de la superclase.
Pensemos ahora que solamente tenemos la clase medios_de_transporte,
podríamos decir que ella se divide en tres: medios de transporte Aéreos,
13
El Paradigma de la orientación a objeto – Conceptos Básicos
terrestres y marítimos. Estas tres últimas clases son una especialización de
medios de transporte.
figura 4: Clases después de la generalización.
La especialización es el proceso mediante el cual definimos una o más
subclases a partir de una superclase, en cambio en la generalización
definimos una superclase a partir de una o más subclases.
Todos los objetos que pertenecen a una subclase también lo son de su
superclase.
Siguiendo el ejemplo anterior, podríamos decir, que un
automóvil XX y una Bicicleta YY, pertenecen a clases distintas, pero a la vez
tienen una clase en común que es Medios_de_transporte.
Si en algún
momento esperamos un objeto de la clase medios de transporte, XX e YY
son perfectamente válidos. Esto no se limita a la superclase directa, también
es válido para las indirectas, es decir, para la superclase de la superclase, y
así sucesivamente.
Cabe mencionar que, existe un tipo de superclase de la cual no se instancian
objetos directamente, ellas reciben el nombre de superclase abstracta.
Dependiendo del número de superclases que posea una clase, podemos
definir dos tipos de herencia: Herencia simple y Herencia múltiple.
La
14
El Paradigma de la orientación a objeto – Conceptos Básicos
herencia simple es aquella donde una subclase puede tener solamente una
superclase.
En la herencia múltiple una subclase puede tener una o más
superclases.
La herencia trae los siguientes beneficios:
•
Elimina redundancia innecesaria. Al definir los atributos y métodos
que son comunes a un grupo de objetos en una superclase se evita
que estos estén repetidos en sus subclases.
•
Facilita la mantención.
Al modificar una superclase se modifican
automáticamente las subclases.
•
Facilita la localización de errores. Al construir una subclase basada
en una superclase libre de errores, cualquier error que aparezca en la
subclase va a ser producto de los métodos que esta introdujo.
•
Reutilización. Al poder heredar métodos y atributos no tenemos que
definirlos nuevamente sólo reutilizarlos, lo que incrementa la
productividad.
Pero ninguno de estos beneficios serían significativos, si no existiera el
polimorfismo.
2.2.5.1.1 Polimorfismo
La idea de polimorfismo es: permitir que diferentes métodos tengan el
mismo nombre [20]. Éste concepto esta íntimamente ligado al de herencia
[2].
Pensemos en una superclase llamada figuras_geométricas, que
tenga como subclases a triangulo, cuadrado, circulo.
Pensemos que
tenemos un arreglo de figuras geométricas y queramos dibujar cada una
de ellas.
Una alternativa es la siguiente implementación (en pseudo
código):
Inicio
Defina A[1..10] de figuras_geométricas
Llenar el arreglo A con figuras_geométricas
Para i = 1 hasta 10 haga
En caso que A[i] sea
triangulo entonces A[i].dibujarTriangulo
cuadrado entonces A[i].dibujarCuadrado
circulo
entonces A[i].dibujarCirculo
fin en caso que
Fin Para
15
El Paradigma de la orientación a objeto – Conceptos Básicos
Fin
Esto se puede simplificar enormemente.
Podemos agregar un método
llamado Dibujar en la superclase Figuras_geométricas. De esta manera
todas las subclases tendrían este mismo método.
subclases
tiene
un
modo
particular
de
Cada una de sus
dibujarse,
esto
se
logra
redefiniendo la implementación del método. Esta redefinición también se
denomina suplantación o anulación (overriding)
porque la definición
particular ocupa el lugar de la definición general (la suplanta) [2]. De esta
manera logramos tener un mismo nombre de método, pero diferentes
implementaciones de él.
De este modo el algoritmo antes presentado se reduce a :
Inicio
Defina A[1..10] de figuras_geométricas
Llenar el arreglo A con figuras_geométricas
Para i = 1 hasta 10 haga A[i].Dibujar()
Fin
Esto trae como consecuencia un diseño más simple, una herencia más
efectiva, y en casos como el ejemplo anterior, menos líneas de código.
Para lograr esta nueva funcionalidad el sistema tiene que asociar la
invocación al método con el método correspondiente en tiempo de
ejecución. Esto se denomina ligadura tardía (late binding) [2].
Otra manera de lograr el polimorfismo es la sobrecarga de métodos. Esta
consiste en tener dos o más métodos con el mismo nombre pero con
distintos argumentos. En este caso no es necesario hacer una ligadura
tardía, se puede hacer de manera normal, es decir, en momento de
compilación (enlace más temprano).
2.2.5.2 Asociación
Las clases se asocian para poder interactuar entre sí. La asociación es un
enlace físico o conceptual que permite a un objeto ocupar los servicios
(métodos) de otro. Este enlace es bidireccional a menos que se especifique lo
contrario. Además este enlace posee una multiplicidad, por ejemplo:
•
Uno a uno
16
El Paradigma de la orientación a objeto – Conceptos Básicos
•
Cero a Muchos
•
Uno a muchos
•
Muchos a muchos.
Una asociación entre clases es similar al concepto de relación entre entidades
en un Diagrama Entidad-Relación [1].
2.2.5.3 Agregación y Composición
La agregación es una asociación que representa una relación Todo-Parte
donde un objeto es parte de otro [39]. Al todo se le denomina agregado y
sus partes pasan a ser atributos [4]. En la agregación, las partes, pueden
tener una existencia independiente a la del agregado, pudiendo formar parte
de varias clases, o de ninguna. Un ejemplo, es una comisión compuesta por
varias personas, donde algunas de ellas, no participarán en una comisión,
pero otras participarán en una o varias.
La composición es una forma más fuerte de agregación, donde las partes
sólo podrán pertenecer a un todo, y estás no existirán fuera del contexto del
agregado. La única forma de acceder a las partes será a través del todo [4].
Por ejemplo podemos definir una clase bicicleta como una composición de las
siguientes clases: rueda, pedal, manubrio, cadena, freno, asiento, marco.
Donde la clase rueda puede ser un agregado de rayos, eje, cámara,
neumático.
Mediante
la
agregación
y
la
composición
podemos
definir
objetos
arbitrariamente complejos.
2.2.6 Tipos (tipificación)
Los conceptos de clases y tipos son muy similares, puesto que una clase es la
implementación de un tipo, pero los tipos ponen énfasis en el significado de
una abstracción de manera diferente: “Los tipos son la puesta en vigor de la
clase de los objetos, de modo que los objetos de tipos distintos no pueden
17
El Paradigma de la orientación a objeto – Conceptos Básicos
intercambiarse o, como mucho, pueden intercambiarse sólo de formas muy
restringidas.” [4] página 74.
El objetivo de contar con tipos, es evitar que se mezclen abstracciones de
manera equivocada.
Para lograrlo se debe realizar una comprobación de
tipos, durante el proceso de compilación, que puede ser estricta o débil.
Mediante la comprobación estricta de tipos se pueden detectar errores como:
referencias a atributos inexistentes, invocación de métodos inexistentes,
invocación de métodos con parámetros no válidos (Ej.: se espera un objeto
del tipo automóvil, pero se recibe una del tipo persona), y cualquier otro que
cause una incongruencia de tipos. En los lenguajes de comprobación débil
de tipos, es posible ignorar o suprimir las reglas sobre los tipos.
Existen lenguajes sin tipos como Smalltalk, donde los errores como
invocación de método inexistente solo son reconocidos en tiempo de
ejecución [4].
La ventaja de contar con un sistema que soporte la comprobación estricta es
la detección temprana de errores de incongruencia de tipos en forma
automática, puesto que un error de tipos en tiempo de ejecución no se
manifiesta hasta que esa línea de código es ejecutada y eventualmente
podríamos pasarla por alto en las pruebas de software.
2.2.7 Concurrencia
La concurrencia es transversal a varios paradigmas de la computación. Ésta
consiste en dividir un programa en dos o más procesos que se ejecutarán
simultáneamente, logrando así una mayor eficiencia [6].
Se
pueden distinguir dos tipos de procesos: pesados
y ligeros (hilos),
donde los procesos pesados consumen más recursos computacionales que
los ligeros. Estos procesos se pueden ejecutar en una sola CPU, utilizando
algún algoritmo de tiempo compartido, o en varias, logrando un proceso
verdaderamente concurrente (o paralelo) [4].
18
El Paradigma de la orientación a objeto – Conceptos Básicos
Un modelo objeto que incorpora la concurrencia, considera que cada objeto
puede ser representado por un proceso (o hilo) separado, pasando a ser un
objeto activo. Los objetos activos funcionan independientemente, pero
cooperando con el resto de los objetos, además, sincronizándose cuando sea
necesario.
A partir de esto se puede definir la concurrencia como:
“La
concurrencia es la propiedad que distingue un objeto activo de uno que no
está activo.” [4] página 83.
2.2.8 Persistencia
Cuando desarrollamos un software orientado a objeto y lo implementamos
con algún lenguaje de programación apropiado nos encontramos con la
siguiente pregunta ¿cómo puedo almacenar los objetos en memoria
secundaria?. Esto sucede porque los lenguajes de programación orientados a
objeto, en su mayoría, no permiten almacenar en forma directa un objeto o
una jerarquía de objetos en memoria secundaria, y solamente los crean,
manipulan y destruyen en memoria principal. Este es el problema de la
persistencia, es decir, permitir que un objeto (o una jerarquía completa) sea
almacenado en un soporte auxiliar no volátil, con el objetivo de ser usado
nuevamente por la aplicación que lo creó o por otra aplicación [21].
Es
impensable tener un software que cada vez que se inicie tenga que ingresar
todos sus datos, como por ejemplo, una lista de clientes y de productos.
2.2.8.1 Formas de solucionar el problema de la persistencia
Para solucionar el problema de la persistencia tenemos las siguientes
alternativas [21]:
•
Archivos convencionales
•
Bases de datos relacionales
•
Bases de datos orientadas a objetos (puras y objeto- relacional).
2.2.8.1.1 Archivos convencionales
Los archivos convencionales son los archivos básicos que puede manejar
todo lenguaje de programación, estos no tienen ningún soporte directo
19
El Paradigma de la orientación a objeto – Conceptos Básicos
para los objetos, por lo tanto tenemos que crear nuestros propios
protocolos para almacenarlos. Un caso especial es el lenguaje Smalltalk el
que cuenta con protocolos para escribir y leer objetos en discos [4]. En
cualquiera de los dos casos, esta solución para la persistencia, es muy
limitada, y solo sería aconsejable para entornos monousuarios que no
necesiten manejar grandes cantidades de datos.
2.2.8.1.2 Bases de datos relacionales
Un Software de administración de bases de datos relacional (SABDR) es
nuestra
segunda
solución.
Gracias
a
sus
características
(como
concurrencia, transacciones, réplica, backup, auditoría, etc.) podemos
implementar aplicaciones que necesiten mantener gran cantidad de
información y manejo de múltiples usuarios concurrentes.
En este caso también será necesario implementar la persistencia por
nosotros mismos lo que incrementa la complejidad y el tiempo de
desarrollo de nuestra aplicación y con ello, los costos.
Ambas soluciones no permiten que los objetos persistentes sean
independientes a la aplicación creada. Esto es necesario cuando varias
aplicaciones distintas tienen que utilizar los mismos objetos.
2.2.8.1.3 Bases de datos orientadas a objetos.
Hoy en día, existen en el mercado sistemas de bases de datos diseñadas
para almacenar objetos, si bien no son perfectas, nos brindan una serie de
características, que nos facilitan esta tarea (Ej.: O2, Object Store, Orión,
etc). Además tienen características propias de los SABD y logran que el
objeto persistente sea independiente de la aplicación. Esta independencia
se logra almacenando las jerarquías de clases, junto con los objetos, en la
base de datos.
En las tres soluciones existe un problema denominado falta de
correspondencia
(impedance mismatch) [2], este se produce cuando
20
El Paradigma de la orientación a objeto – Conceptos Básicos
alguna característica del lenguaje orientado a objeto no está presente en
nuestra solución.
La falta de correspondencia es completa en las dos
primeras soluciones y en la tercera, ésta es casi nula.
Dentro de esta línea existen dos tendencias importantes. Estas son las
bases de datos objeto relacional (SABDOR) y las bases de datos orientadas
a objetos puras (SABDOO).
En el siguiente capítulo hablaremos con
detenimiento sobre ambas.
21
3 Bases de datos Orientadas a
Objeto
3.1 Introducción
Los sistemas de Administración de bases de datos (SABD) nacen en los años
60, como solución a los problemas de manejo de archivos.
Mario Piattini
explica la evolución de los SABD definiendo tres generaciones [13].
La
primera generación constituida por los sistemas jerárquicos (IMS, Total, etc.)
y en Red (IDMS, AIM, IDS, etc.); la segunda por los sistemas relacionales
(Oracle, DB2, Ingres, Informix, Sybase, etc.); y una tercera generación
representada por los SADB orientados a objetos (SABDOO), deductivos,
activos, multimedia, temporales, federadas, móviles y otros [40].
3.1.1 Bases de datos relacionales
La segunda generación ha sido motivo de investigación durante más de 20
años, consolidándose en el mercado.
Los SABD relacionales tienen
fundamentos teóricos sólidos introducidos por Codd en 1970 [10]. Estos se
basan en una estructura de datos simple y uniforme llamada Relación.
Los SABD relacionales se caracterizan por [10]
•
Persistencia. Esta característica es la esencia de las bases de datos,
guardar la información en memoria secundaria hasta que sea
explícitamente borrada.
•
Existencia de un catálogo o diccionario de datos.
información
sobre
la
estructura
de
las
tablas
Éste contiene
(relaciones)
y
restricciones sobre la manipulación de los datos.
•
Abstracción de los datos.
Los SABD ofrecen a los usuarios una
representación conceptual de los datos, ocultando los detalles de
almacenamiento.
•
Independencia entre programas y datos.
Gracias a esto los datos
pueden ser utilizados por distintos programas.
Esto se logra
almacenando la estructura de los archivos en la base de datos
(catálogo).
23
Bases de Datos orientadas a objeto - Introducción
•
Manejo de múltiples vistas de usuario. Las vistas permiten mostrar
a los usuarios solamente lo que necesitan o les es permitido “ver” de
la base de datos.
•
Gestión de transacciones concurrentes.
Esto permite que dos o
más usuarios utilicen los mismos datos simultáneamente, en forma
controlada.
•
Lenguaje de consulta SQL. Es un lenguaje declarativo que permite
interrogar a la base de datos para buscar información. Se basan en el
estándar SQL.
3.1.2 Bases de datos orientadas a objeto
Los SABD orientados a objeto son la unión entre las características propias de
las bases de datos y del paradigma de la orientación a objeto.
De esta
manera, las bases de datos no sólo almacenan información, sino que también
algoritmos. Éstas nacen para solucionar el problema de la persistencia en
forma
eficiente
(ver
sección
2.2.6.1),
requisito
indispensable
para
aplicaciones como: CASE (Ingeniería de software asistida por computador),
CAD/CAM (Diseño / fabricación asistidos por computador), SIG (Sistemas de
información geográficos), multimedia, gestión de redes
[14]; donde los
sistemas relacionales han sido incapaces de satisfacer los requerimientos de
dichas aplicaciones.
Los SABDOO están creciendo
rápidamente (sobre un 300% en 1995 [13]),
pero todavía representan un mínimo porcentaje respecto al total de los
sistemas instalados (5% del mercado mundial de bases de datos en 1997
[40]).
3.1.2.1 Nuevos requerimientos
Por la necesidad de almacenar objetos persistentes, las Bases de datos OO
deberán satisfacer un conjunto de requisitos que están estrechamente
ligados a los conceptos básicos del paradigma de la orientación a objeto.
Estos son:
24
Bases de Datos orientadas a objeto - Introducción
•
Definición de clases y extensión de los tipos de datos primitivos.
La definición de clases y su jerarquía debe formar parte del catálogo,
además es deseable que estas clases pasen a formar parte del sistema
de tipos del SABD.
•
Lenguajes de programación computacionalmente completos. Los
SABD deben contar con leguajes de programación o interfaces con
lenguajes para implementar los métodos de los objetos.
•
Objetos complejos1. Para poder implementar este tipo de objetos es
necesario contar con mecanismos que permitan tener atributos
multivaluados (como listas, conjuntos, arreglos, etc.), identificadores
únicos y referencias a otros objetos.
•
Herencia, Encapsulamiento y Polimorfismo.
Estos son pilares
fundamentales de la orientación a objeto, por lo que deben
considerarse.
•
Manejar
versiones
de
objetos
y
configuraciones.
Cuando
cambiamos los valores de los atributos, estos son reemplazados por
los nuevos. En algunas aplicaciones es necesario conocer los valores
históricos que han asumido los objetos, esto se logra manejando
distintas versiones del objeto. Una configuración establece enlaces
entre una versión de un objeto compuesto y las correspondientes
versiones de sus objetos componentes.
•
Evolución de esquemas y de instancias. Los cambios en este tipo
de sistemas son la regla más que una excepción.
Para ello es
necesario
modificar
proveer
de
mecanismos
que
permitan
la
definición de las clases y sus jerarquías (Evolución de esquemas),
además de soportar la migración de instancias entre clases.
•
Transacciones de larga duración. Como los objetos y sus atributos
pueden ser bastante grandes (Ej.: un video en una base de datos
multimedia), las transacciones pueden ser bastante largas. Por eso se
deben reconsiderar los mecanismos de recuperación ante un fallo y el
control de la consistencia.
1
Objeto donde uno de sus atributos es otro objeto o un grupo de objetos.
25
Bases de Datos orientadas a objeto - Introducción
•
Mecanismos de autorización basados en la noción de objetos.
los sistemas tradicionales,
En
los mecanismos de autorización están
asociados a una relación o a una vista. Estos mecanismos no son del
todo adecuados para un modelo orientado a objeto, el que necesita
mecanismos asociados a la noción de objetos, considerando la
herencia, versiones, objetos compuestos, etc.
•
Interactuar con sistemas existentes. Es necesario que estos nuevos
sistemas sean capaces de acceder y manipular datos en sistemas
existentes como bases de datos relacionales, debido al impacto que
tiene en una organización la migración de datos.
26
3.2 Estándares de SABDOO
En general, existen dos clases de normas, una de ellas llamada de Jure (por
ley) que corresponde a aquellos estándares publicados por organizaciones
dedicadas a ello y reconocidas internacionalmente (Ej.: ANSI, ISO, IEE);
Y
otras llamadas de facto (de hecho) que corresponden a aquellos estándares
que realmente están en uso en el mercado sean estos o no, publicados por
una organización formal de estandarización.
Asociados a las bases de datos orientadas a objetos, existen dos estándares:
SQL:1999 y ODMG v2.0 [13], el primero “de Jure” (y de facto) y el segundo
“de facto”.
Estos dos estándares siguen tendencias distintas, pero que están
convergiendo. Estas tendencias son:
•
Extender los SABD relacionales para que soporten la orientación a
objetos (SQL:1999);
•
confeccionar un SABDOO basado en un modelo de objetos “puro” que
no extienda sistemas relacionales (ODMG-93).
3.2.1 Las tendencias: SABD relacionales “Extendidos” vs.
SABDOO “Puros”
Ambas tendencias tienen un manifiesto que recoge las características que
debe tener un SABDOO, según su punto de vista.
denomina
El primero de ellos se
“Manifiesto de los sistemas de bases de datos de tercera
generación”,
propuesto por Carey et al. en 1991 [13] [14], y es el que
promueve extender los SABD relacionales.
Este manifiesto presenta tres
principios que se desarrollan en trece preposiciones. El siguiente resumen
está sacado textualmente de [13]:
1. Principio: “además de los servicios tradicionales de gestión de datos, los
SABD de la tercera generación proporcionaran gestión de objetos y reglas
más ricos”
•
Un SABD de tercera generación debe tener un rico sistema de tipos
27
Bases de Datos orientadas a objeto – Estándares de SABDOO
•
La herencia es una buena idea
•
Las
funciones
(incluyendo
procedimientos
y
métodos)
y
el
encapsulamiento, son una buena idea.
•
Se deberían asignar identificadores de objeto para los registros sólo si
no está disponible una clave primaria
•
Las reglas se convertirán en una característica primordial de los
futuros sistemas.
2. Principio: “Los SABD de tercera generación deben subsumir a los SABD de
segunda generación”
•
Un SABD de la tercera generación debe tener un lenguaje de acceso
declarativo y de alto nivel
•
Deben existir
dos
formas
de
especificar
las
colecciones:
por
enumeración de sus miembros o mediante un lenguaje de consultas
•
Las vistas deben ser actualizables
•
Los indicadores de resultado no deben aparecer en los datos
3. Principio: “los SABD de tercera generación deben ser abiertos a otros
subsistemas”
•
Un SABD de la tercera generación debe ser accesible desde múltiples
lenguajes de alto nivel
•
Se debe soportar la persistencia de las variables
•
El SQL es una forma "intergaláctica" de expresión de datos
•
Las consultas y sus respuestas deben ser el nivel más bajo de
comunicación entre un cliente y un servidor
Este manifiesto deja en claro la idea de extender los sistemas relacionales
actuales, manteniendo una compatibilidad hacia atrás. Este enfoque también
llamado "evolutivo" es el que han adoptado la mayoría de los fabricantes de
SABD relacionales (Oracle, Informix, Sybase, etc). A los SABDOO que siguen
este enfoque también se les denomina SABD objeto relacional (ORDBMS o
SABDOR), por combinar ambos paradigmas.
La segunda tendencia se plasma en el manifiesto denominado "Manifiesto de
los Sistemas de Bases de Datos Orientadas al Objeto", propuesto por
28
Bases de Datos orientadas a objeto – Estándares de SABDOO
Atkinson en 1989 [13], es el que recoge el punto de vista de los SABDOO
“puros”. Mario Piattini resume este manifiesto de la siguiente manera [13]:
[En este manifiesto se recogen] trece "características obligatorias" o "reglas
de oro" que deben cumplir todos los SABDOO, y que afectan a:
•
objetos complejos
•
identidad del objeto
•
encapsulamiento
•
tipos y clases
•
jerarquías de tipos o clases
•
anulación, sobrecarga y vinculación (binding) dinámica
•
completitud de cálculos
•
extensibilidad
•
persistencia
•
gestión del almacenamiento secundario
•
concurrencia
•
recuperación
•
facilidad de consulta "ad hoc"
Junto a cinco "características opcionales" que sería deseable que presentaran:
•
herencia múltiple
•
verificación e inferencia del tipo
•
distribución
•
transacciones de diseño
•
versiones
Además exponen "opciones abiertas" a los fabricantes de los SABDOO, como
pueden ser:
1. paradigma de programación
2. sistema de representación
3. sistema de tipos
4. uniformidad
De este manifiesto se desprende que el paradigma de la orientación a objeto
debe ser soportado fuertemente, además no se mencionan los elementos del
modelo relacional, ni tampoco una compatibilidad con los estándares
actuales de bases de datos relacionales. Por esto podríamos decir que este
29
Bases de Datos orientadas a objeto – Estándares de SABDOO
enfoque pretende crear un SABDOO puro, porque no mezcla orientación a
objeto con los conceptos relacionales.
Independiente del enfoque que adopten los SABDOO, el que “gane la batalla”,
será aquel que: brinde el soporte más completo al paradigma de la
orientación a objeto, sea compatible con las bases de datos relacionales, sea
un SABD de alto rendimiento y logre una integración transparente entre el
lenguaje de programación y la base de datos.
En este momento, no existe
un producto que reúna todas estas características, pero siguen trabajando en
ello.
3.2.2 Estándar SQL:1999
El estándar SQL:1999 sigue el enfoque “evolutivo”, puesto que es la última
versión
aprobada
del
estándar
SQL.
Éste
estándar
incorpora
varias
características del paradigma de la orientación a objeto al enfoque relacional,
pero no se limita a eso, puesto que incorpora otras características (véase el
siguiente capítulo) y reestructura completamente la documentación del
estándar, en vistas a una progresión más rápida en el futuro [8].
Durante su desarrollo se conoció como SQL 3, y a partir de los borradores de
trabajo del estándar, se desarrollaron varios ORDBMS entre ellos: Oracle 8 de
Oracle, Universal Server de Informix, DB2 Universal Database de IBM,
Cloudscape de Cloudscape, entre otros.
En el capítulo 5 se analizará el
ORDBMS Oracle 8i.
3.2.2.1 Origen y evolución
SQL nace a partir de SEQUEL, un lenguaje de consulta de bases de datos
relacionales desarrollado por IBM en 1976-77 [10].
En 1979 aparece el
primer SABDR comercial basado en SQL, Oracle. Luego de este, aparecieron
muchos otros SABDR basados en SQL como: DB2, Interbase, Sybase, etc; y
otros, que no lo tenían como lenguaje base, empiezan a ofrecer interfaces
SQL. De esta manera, el SQL pasa a ser un estándar de facto [15].
30
Bases de Datos orientadas a objeto – Estándares de SABDOO
El primer estándar de Jure de SQL es el SQL/ANS (SQL-86), aprobado en 1986,
por ANSI, al año siguiente fue aprobado por ISO. En 1989 se publica una
nueva versión del estándar que incorpora una integridad referencial básica.
En 1992 se aprueba la siguiente versión de SQL, llamada SQL-92. En esta
versión, se incrementa sustancialmente la capacidad semántica del esquema
relacional, añadiendo nuevos operadores, mejorando el tratamiento de
errores incorporando normas para el SQL embebido. Dos partes adicionales
se desarrollan también en 1992 el SQL/CLI y el SQL/PSM [8].
La última
versión del estándar, fue aprobada por ANSI e ISO en 1999, llamándose
SQL:1999 (No se llamó SQL-99 para no sufrir el problema del 2000), en este
mismo año ISO aprueba el SQL/Multimedia.
3.2.2.2 Partes que lo componen
El estándar está dividido en cinco documentos o partes:
Número de Documento
Nombre del documento
1. ANSI/ISO/IEC 9075-1-1999
Informatión
Technology
–
Database
Languages – SQL – part 1: Framework
(SQL/Framework)
2. ANSI/ISO/IEC 9075-2-1999
Information
Technology
–
Database
Languages – SQL – part 2: Foundation
(SQL/ Foundation)
3. ANSI/ISO/IEC 9075-3-1999
Information
Technology
–
Database
Languages – SQL – part 3: Call-level
Interface (SQL/CLI)
4. ANSI/ISO/IEC 9075-4-1999
Information
Technology
–
Database
Languages – SQL – part4: Persistent
Stored Modules (SQL / P SM)
5. ANSI/ISO/IEC 9075-5-1999
Information
Technology
–
Database
Languages – SQL – part 5: Host Language
Bindings (SQL/Binding)
Cada
una
de
las
partes
puede
ser
adquirida
por
separado
en
http://web.ansi.org.
31
Bases de Datos orientadas a objeto – Estándares de SABDOO
3.2.3 Estándar ODMG 2.0
El estándar ODMG 2.0, es al que se acogen las empresas de SABDOO “Puros”,
y a diferencia de SQL:1999, es un estándar de facto, cuya primera versión
apareció hace siete años.
3.2.3.1 Origen y evolución
En verano de 1991, se reunió un grupo de expertos que trabajaban en
distintas empresas de SABDOO, para elaborar un estándar de facto, basado
en las características que presentaban los productos existentes y que se
pudiera publicar en un corto
plazo.
Así nació el ODMG (Object Data
Management Group) que actualmente agrupa a los principales vendedores de
SABDOO [13]: Object Design, Ontos, O2 Technology, Versant, Objectivity,
POET Software y Servio Corporation; y que cuenta también con diversos
revisores tanto de empresas (Andersen, Hewlett-Packard, EDS, Sybase, Texas
Instruments o Persistence), como de universidades: Maier, Dewitt, Carey,
Dittrich, Zdonik, Liskov, King, etc. En 1993 ODMG publica la primera versión
de este estándar, el ODMG-93, una versión mejorada de este es publicada en
1995, el ODMG-93 v 1.2, en 1997 el ODMG 2.0 y la última versión publicada
de este estándar es ODMG 3.0, publicada en el año 2000.
3.2.3.2 Partes que lo componen
Este estándar se divide en las siguientes partes [19]:
•
Modelo de Objetos.
Este está basado en el aprobado por el OMG
(Object Management Group) y extendido con los conceptos propios de
las bases de datos.
•
Lenguaje de Definición de Objetos.
Se utiliza para describir la
interfaz de los objetos. Su sigla es ODL (Object Definition Language)
y está basado en IDL (Interface Definition Language) de CORBA
(Common Object Request Broker Architecture).
•
Lenguaje de Consulta de Objetos. Este lenguaje es similar a SQL,
pero no es compatible con él. Sus siglas originales son OQL (Object
Query Language).
32
Bases de Datos orientadas a objeto – Estándares de SABDOO
•
Vinculación con el lenguaje C++
•
Vinculación con el lenguaje Smalltalk
•
Vinculación con Java
Para la vinculación con los lenguajes de programación este estándar ha
procurado que el programador piense que utiliza un solo lenguaje. Esto lo
logra integrando el lenguaje anfitrión con el lenguaje de manipulación de
datos en forma natural y consistente [13].
Cabe destacar, que algunos SABDOO dan soporte a características que no son
consideradas en el modelo objeto relacional, como la herencia múltiple (Ej.:
IRIS, O2) y el manejo de versiones y configuraciones (Ej.: Orion). Puede ver
un estudio comparativo, sobre las características de un grupo representativo
de bases de datos orientadas a objeto en [2].
33
4 La Orientación a Objeto en
SQL:1999
4.1 Introducción
En el capítulo anterior, explicamos la historia que hay detrás de SQL:1999,
además de las partes que lo componen y dónde conseguirlo.
profundizaremos más en el tema,
Aquí
partiendo por las organizaciones
internacionales dedicadas a la estandarización de SQL:1999, las mejoras que
introduce con respecto a su antecesor, y se evaluará el soporte que da a la
Orientación a objeto, basándonos en el capítulo 2 y la sección 3.1.2.1.
4.1.1 Organizaciones preocupadas de la estandarización de
SQL
El primero en publicar un estándar para SQL (SQL-86) fue
el instituto
estadounidense para la estandarización ANSI (American National Standards
Institute), y desde entonces ha sido un actor fundamental dentro del proceso
de estandarización de SQL.
Dentro de su esquema de trabajo, ANSI, no
desarrolla las normas por si mismo, más bien acredita a otras organizaciones
para que desarrollen los estándares bajo su auspicio y sus reglas [7] [8].
ANSI ha publicado varias normas referentes a tecnologías de la información a
través
de
varios
acreditados
diferentes
(SDO
-Standards
Developing
Organization), incluyendo a IEEE y un grupo llamado NISO (National
Information Standards Organization). La mayoría de los estándares asociados
con
las
tecnologías
de
la
información publicadas por
ANSI fueron
desarrollados por un grupo, conocido anteriormente con el nombre de X3
(entre 1961 – 1996) y ahora denominado NCITS (National Committee for
Information Technology Standards).
Este grupo crea comités técnicos que
son los que realmente hacen el trabajo.
Uno de estos comités es el H2
(anteriormente conocido como X3H2 y ahora como NCITS H2) que es el
encargado de desarrollar una serie de estándares asociados a las bases de
datos entre ellos RDA (Acceso a bases de datos remotas), SQL y SQL/MM.
En el ámbito internacional, el principal cuerpo de desarrollo de estándares es
ISO (International Standards Organization) y es quien tiene el rol oficial de
desarrollo de normas internacionales. Este, al igual que ANSI,
coopera con
35
La Orientación a Objeto en SQL:1999 - Introducción
otras organizaciones, siendo una de ellas IEC (International Electro technical
Comision).
Del esfuerzo conjunto entre ISO e IEC nace el JTC1 (Joint
Technical Committee 1) cuya misión es desarrollar y mantener estándares
relacionados a tecnologías de la Información. El JTC1 crea subcomités (SCs)
para distintas áreas de las tecnologías de la información. Hasta más o menos
1997 el SC21 era el responsable de SQL, pero luego de su disolución, esta
responsabilidad fue asignada a un nuevo comité llamado SC32.
Este
Subcomité se encarga de los estándares asociados a las bases de datos y a
los meta datos (RDO, SQL, SQL/MM, etc). Para esto crea, a su vez grupos de
trabajo (Working Group), entre ellos destacamos el WG3 que es el encargado
del estándar SQL y el WG4 que se encarga del SQL/MM.
En total son 28
países los que integran el JTC1 y sus respectivos subcomités y grupos de
trabajo. Alguno de estos miembros y sus institutos de estandarización son :
Canadá (SCC), Australia (SAA), Brasil (ABNT), China (CSBTS), Francia (AFNOR),
Alemania (DIN), Italia (UNI), Japón (JISC), Reino Unido (BSI), Estados Unidos
(ANSI).
Para más información sobre estas organizaciones y los procesos actuales de
estandarización visite los siguientes sitios web:
•
American National Standards Institute (ANSI)
o
•
National Committee for Information Technology Standards (NCITS)
o
•
http://www.iso.ch
International Electro technical Commission (IEC)
o
•
http://www.ncits.org/tc_home/h2.htm
International Organization for Standardization (ISO)
o
•
http://www.ncits.org
NCITS H2
o
•
http://www.ansi.org
http://www.iec.ch/
Joint Technical Committee 1(JTC1)
o
http://www.jtc1.org/
36
La Orientación a Objeto en SQL:1999 - Introducción
4.1.2 Nuevas características.
Las nuevas características del estándar SQL:1999, se pueden dividir en
“Características Relacionales” y “Características Orientadas a Objeto”. En esta
sección nos limitaremos a describir las “Características relacionales y en la
sección 4.2, explicaremos las referentes a la orientación a objeto.
4.1.2.1 Nuevos Tipos de Datos
SQL:1999 tienen cuatro nuevo tipos de datos. El primero de estos tipos es el
LARGE OBJET, o LOB. Este tipo tiene las siguientes variantes: CHARACTER
LARGE OBJECT (CLOB) y BINARY LARGE OBJECT (BLOB).
Otro nuevo tipo de datos es BOOLEAN que le permite a SQL grabar
directamente los valores de verdad: verdadero (true), falso (false), y
desconocido (Unknown) [25].
SQL:1999 también incorpora dos tipos compuestos: ARRAY y ROW [8] [25]. El
tipo ARRAY nos permite guardar colecciones de valores directamente en una
columna de una tabla de la base de datos. Por ejemplo:
DIAS_DE_LA_SEMANA VARCHAR(10) ARRAY[7]
El tipo ROW en SQL:1999 es una secuencia de una o más parejas (<Nombre
Campo>,<Tipo de datos>) llamados campos (fields) [25] que permite
almacenar valores estructurados en simples columnas de la base de datos.
Por ejemplo:
CREATE TABLE employee (
EMP_ID INTEGER,
NAME
ROW (GIVEN
VARCHAR(30),
FAMILY VARCHAR(30)),
SALARY REAL )
SELECT E.NAME.FAMILY FROM
employee E
SQL:1999 agrega además otro tipos de datos llamados “tipos distintos”, que
son tipos de datos definidos por el usuario (UDT en adelante) que se basan
en tipos primitivos o en otros tipos distintos[25]. Por ejemplo:
37
La Orientación a Objeto en SQL:1999 - Introducción
CREATE TYPE SHOW_SIZE AS INTEGER(3) FINAL
CREATE TYPE IQ AS INTEGER(3) FINAL
...
WHERE MY_SHOE_SIZE > MY_IQ
// ERROR
En este ejemplo, la última expresión arrojaría un error de sintaxis, puesto que
MY_SHOE_SIZE y MY_IQ son de distinto tipo.
4.1.2.2 nuevos predicados
En SQL:1999 existen dos nuevos predicados que no se relacionan con la
orientación a objeto, el predicado SIMILAR y el predicado DISTINCT [8].
El predicado SIMILAR es utilizado para definir expresiones regulares para la
búsquedas de patrones como lo hacen los programas UNIX. Por ejemplo:
WHERE NAME SIMILAR TO
' (SQL-(86|89|92|99)) | (SQL(1|2|3)) '
En este ejemplo se emparejarían varios nombres dados al estándar SQL
durante los años. [8].
El otro predicado nuevo, DISTINCT, es muy similar en operación al predicado
ordinario UNIQUE de SQL; Dos valores nulos no son distintos (DISTINCT), si
únicos (UNIQUE) [14].
4.1.2.3 semántica reforzada
SQL:1999 ha aumentado significativamente el alcance de vistas que pueden
actualizarse directamente, facilitando así su utilización .
Una limitación de SQL ha sido su incapacidad para ejecutar recursión [8] [24],
pero
esto
ha
sido
solucionado
en
característica llamada Recursive Query.
SQL:1999
proporcionando
una
Definir una consulta recursiva
involucra escribir la expresión de consulta que usted quiere recurrente,
entonces usa ese nombre en una expresión de consulta asociada.
Por
Ejemplo
38
La Orientación a Objeto en SQL:1999 - Introducción
WITH RECURSIVE
Q1 AS SELECT...FROM...WHERE...,
Q2 AS SELECT...FROM...WHERE...
SELECT...FROM Q1, Q2 WHERE...
Otra funcionalidad incorporada es la noción de savepoints. Ellos permiten, a
una aplicación, deshacer las acciones realizadas después del principio de un
savepoint sin deshacer todas las acciones de una transacción entera[8].
SQL:1999 permite ROLLBACK TO SAVEPOINT y RELEASE SAVEPOINT [26].
4.1.2.4 seguridad adicional
La nueva característica de seguridad de SQL:1999 se encuentra en su
capacidad de creación de roles (o papeles) [8]. Pueden concederse privilegios
a los papeles y estos pueden ser identificadores de autorización individual o
conceder privilegios de autorización a otros papeles. Por ejemplo [14]:
CREATE ROLE Administrador
CREATE ROLE Jefe_Supremo
GRANT Administrador TO Miguel
GRANT Administrador TO Jefe_Supremo
4.1.2.5 bases de datos activa
SQL:1999 reconocen la noción de base de datos activa, aunque algunos años
después que los SABD lo hicieran. Esta facilidad es proporcionada a través de
una característica conocida como disparador (trigger). Un disparador es una
facilidad que les permite a los diseñadores de la base de datos instruir al
sistema para ejecutar ciertos procedimientos cada vez que una aplicación
realice operaciones específicas en tablas particulares [8] [26].
Por ejemplo, podrían usarse disparadores para anotar todas las operaciones
que cambian sueldos en una tabla empleado [8]:
CREATE TRIGGER log_salupdate
BEFORE UPDATE OF salary
ON employees
REFERENCING OLD ROW as oldrow
NEW ROW as newrow
FOR EACH ROW
INSERT INTO log_table
VALUES (CURRENT_USER, oldrow.salary, newrow.salary)
39
4.2 Soporte a la Orientación a objeto
Para analizar el soporte de la orientación a objeto en SQL:1999, nos
basaremos en los conceptos básicos de la orientación a objetos (ver 2) y en
los requerimientos para bases de datos orientadas a objetos (ver 3.1.2.1 ).
Por motivos didácticos el orden de los conceptos será diferente. La sintaxis
de SQL:1999 relacionada con la orientación a objeto, se encuentra en el
apéndice A.
4.2.1 Tipos, abstracción y clases
El estándar unifica estos conceptos bajo el nombre de tipo estructurado, que
es otro tipo de UDT. Un tipo estructurado encapsula atributos y métodos en
una única entidad lógica, pero físicamente separados. Los atributos de un
objeto persistente los almacenaremos en una tabla, y los métodos, junto con
los demás procedimientos almacenados. Cabe destacar que esta separación
será transparente para el usuario.
Este nuevo tipo, pasará a ser uno más del sistema, pudiendo ser utilizado del
mismo modo que un tipo primitivo.
4.2.1.1 Creación de tipos (CREATE TYPE)
Para crear un tipo estructurado se utiliza el predicado CREATE TYPE [26],
donde especificamos una lista de atributos, y opcionalmente, una lista de
métodos (ver A.2.1).
Por ejemplo, consideremos un tipo Punto, con los atributo: X, Y; y con los
métodos: moverA(x,y), distanciaA(p), crear(x,y); su implementación sería:
CREATE TYPE punto AS
(
X INTEGER ,
Y INTEGER
)INSTANTIABLE NOT FINAL
METHOD moverA(x INTEGER, y INTEGER),
METHOD distanciaA(p Punto) RETURNS FLOAT,
STATIC METHOD crear(x INTEGER, y INTEGER) RETURNS punto
40
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
La cláusula INSTANTIBLE, permite crear instancias del tipo directamente. Si
queremos prohibir esto (para implementar clases abstractas), indicamos NOT
INSTANTIABLE. Esta cláusula es opcional (ver A.2.1), cuyo valor por defecto
es INSTANTIABLE.
La cláusula NOT FINAL, permite que el tipo sea utilizado como supertipo de
otro (ver 4.2.6.3 Herencia y polimorfismo). Esta cláusula no es opcional.
Todo
tipo
estructurado
tiene
asociado
un
correspondiente
tipo
de
referencia. Este tipo almacena una secuencia de bytes, que indica el lugar
donde está almacenado un objeto de ese tipo.
El número de bytes es
dependiente de la implementación del estándar.
Un tipo de referencia puede ser utilizado en los mismos lugares que un tipo
estructurado.
Para definirlos utilizamos la palabra reservada REF, seguida
por el nombre del tipo entre paréntesis. Por ejemplo, consideremos un tipo
linea_recta, definido de la siguiente manera:
CREATE TYPE linea_recta AS
(
a REF(punto),
b REF(punto)
)INSTANTIABLE NOT FINAL
con este tipo de datos, podemos crear redes de objetos.
Por ejemplo,
podemos crear una lista enlazada, un árbol binario, etc.
Al definir un tipo estructurado, podemos indicar la manera en que el sistema
construirá sus referencias. Para eso, debemos escoger entre tres formas de
representación,
definidas
por
la
cláusula
opcional
<reference
type
specification> (ver A.2.1), que es indicada a continuación de la cláusula
<finality>.
•
Las formas de representación son:
USER GENERATED, la referencia se basa en un tipo primitivo, cuyo valor
será proporcionado por el usuario.
La sintaxis es: REF USING <predefined type>. Ejemplo:
CREATE TYPE persona AS
(
Rut
CHAR(12) ,
Nombre CHAR(40)
)INSTANTIABLE NOT FINAL
REF USING INTEGER
41
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
•
SYSTEM GENERATED, la referencia es generada automáticamente por
el sistema. Este es el valor por defecto.
La sintaxis es: REF IS SYSTEM GENERATED Ejemplo:
CREATE TYPE persona AS
(
Rut
CHAR(12) ,
Nombre CHAR(40)
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
•
DERIVED, La referencia se basa en uno o más atributos. Es semejante
a una clave primaria.
La sintaxis es: REF FROM <list of attributes> Ejemplo:
CREATE TYPE persona AS
(
Rut
CHAR(12) ,
Nombre CHAR(40)
)INSTANTIABLE NOT FINAL
REF FROM (Rut)
Una limitación importante de los tipos de referencia, es que sólo pueden
almacenar direcciones de objetos persistentes.
4.2.1.2 Atributos
Un tipo estructurado puede tener uno o más atributos, cada uno con un
nombre, un tipo de datos, y opcionalmente, un valor por defecto (con
DEFAULT) [26]. No podemos definir dos atributos del mismo nombre, para
un mismo tipo estructurado.
El tipo de datos del atributo, puede ser
cualquiera de SQL, incluyendo un UDT [14]. Por ejemplo, si quisiéramos crear
un tipo Direccion con los atributos calle, numero, ciudad y region, sería.
CREATE TYPE Direccion AS
(
calle
CHAR(40),
numero
CHAR(10),
ciudad
CHAR(30),
region
CHAR(30)
)NOT FINAL
Ahora, podemos crear un tipo empleado con un atributo del tipo Dirección
de la siguiente manera:
CREATE TYPE empleado AS
(
rut
CHAR(12),
nombre
CHAR(40),
42
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
sueldoBase INTEGER ,
anticipo
INTEGER DEFAULT 0,
fecha_ing DATE
DEFAULT CURRENT_DATE,
jefe
REF(empleado),
domicilio direccion
)INSTANTIABLE NOT FINAL
Para acceder al atributo de una instancia, lo hacemos de la misma manera
que en JAVA, a excepción de los atributos del tipo REF(...). Por ejemplo, para
acceder al atributo rut, de un empleado e, sería: e.rut, y esto en cualquier
nivel de anidamiento, por ejemplo: e.domicilio.numero.
Para acceder a los atributos cuyo tipo de datos sea REF(...), existe el operador
->. Por ejemplo, si queremos saber el nombre del jefe del empleado, sería:
e.jefe->nombre
No podemos asignar una visibilidad (Ej.: public, private, protected) a los
atributos (característica que estuvo presente en el borrador de trabajo del
año 1997).
directo.
A pesar de esto, el acceso a los atributos de un tipo no es
Para cada atributo, el sistema genera dos funciones, una
observadora y otra mutadora [26]. Por ejemplo, si decimos p.rut, lo que
sucede en realidad es que estamos invocando a la función observadora
rut(p).
estamos
Si realizamos una asignación como p.rut:=’13.131.344-6’,
invocando
implícitamente
a
la
función
mutadora
rut(p,’13.131.344-6’). Lamentablemente, las funciones observadoras y
mutadoras, no pueden ser sobrecargadas [14].
A diferencia de Java, los atributos estáticos no son soportados.
4.2.1.3 Métodos
A contar del SQL-92, se introduce la noción de procedimiento almacenado,
que corresponde a funciones o procedimientos definidos por el usuario, que
pueden ser utilizados en sentencias SQL.
SQL:1999 incorpora una tercera
categoría de procedimiento almacenado, los métodos [8].
Un método, al
igual que una función, posee un nombre, una lista de argumentos (que puede
estar vacía) y un valor de retorno (opcional). La gran diferencia radica en que
un método, está asociado a un UDT estructurado en particular, y no puede
ser invocado Independientemente.
43
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Al definir los métodos en la creación del UDT estructurado, sólo declaramos
su interfaz (función prototipo o encabezado). Para definir su implementación
o cuerpo, utilizamos la sentencia CREATE METHOD (ver A.2.4). El código
que implementa al método, puede ser escrito en SQL (usando las sentencias
computacionalmente completas del SQL/PSM [47]) o en cualquiera de los
lenguajes de programación más tradicionales, incluyendo JAVA [14].
Los métodos pueden ser: métodos de instancia, métodos constructores o
métodos estáticos.
4.2.1.3.1 Métodos de Instancia
Los métodos de instancia, son aquellos que serán invocados a partir de un
objeto concreto. Para definirlos anteponenemos las palabras reservadas
INSTANCE METHOD o simplemente METHOD, seguido por el nombre, la
lista de parámetros (que puede estar vacía) y opcionalmente el tipo del
valor de retorno. Cada elemento de la lista de parámetros está compuesto
por: Modo, nombre y tipo de datos; donde el modo es la manera en la que
se pasa el parámetro, que puede ser IN (entrada), OUT (salida), INOUT(
entrada y salida). Los métodos de instancia, pueden ser sobrecargados.
Por ejemplo, consideremos un tipo triángulo, definido por los tres
vértices que lo componen, y con tres métodos, uno que calcule su área, y
dos para calcular la distancia de un punto al lado más cercano del
triángulo.
CREATE TYPE triangulo AS
(
A punto ,
B punto ,
C punto
)INSTANTIABLE NOT FINAL
METHOD Area() RETURNS FLOAT,
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
INSTANCE METHOD distanciaA(x FLOAT,y FLOAT) RETURNS FLOAT
La Invocación de un método de instancia, se realiza de la misma forma que
accedemos a un atributo. Por ejemplo, si quisiéramos saber el área de un
triángulo t, sería:
...t.Area()
44
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Si t fuera una referencia a un triangulo, la invocación al método area()
sería:
...t->Area()
Los métodos de instancia incluyen, implícitamente un parámetro, cuyo
nombre es SELF, y representa al objeto de la invocación.
Opcionalmente podemos especificar otras características del método (ver
<method characteristic> en A.2.1), las cuales se indican a continuación del
encabezado. La primera de ellas (<language clause>) indica el lenguaje en
el que se programará el método. Si omitimos esta cláusula, el lenguaje
por defecto, es SQL. Por ejemplo, si el método área del tipo triangulo,
mostrado anteriormente, lo quisiéramos programar en pascal, tendríamos
que especificar:
...
METHOD Area() RETURNS FLOAT
LANGUAGE PASCAL
...
La cláusula <parameter style clause> indica cómo debemos pasar los
parámetros. Puede tomar dos valores posibles:
•
PARAMETER STYLE SQL.
Los parámetros son pasados al estilo de
SQL. Para las rutinas externas que utilicen este estilo, es necesario
agregar algunos parámetros para el control de los valores nulos,
valores de retorno y otros parámetros de control.
En general, se
necesitan 2n+4 parámetros para los procedimientos y 2n+6 para las
funciones, donde n es el número de parámetros del método.
•
PARAMETER
STYLE GENERAL.
Cada parámetro del método,
corresponde efectivamente a un parámetro en la implementación.
Para las rutinas externas, es la manera más fácil de pasar parámetros,
porque coinciden uno a uno. El problema existe con los valores nulos,
que no son soportados, es decir, no podemos invocar al método con
parámetros cuyos valores actuales, sean nulo.
Cuando esta cláusula es omitida, se asume PARAMETER STYLE SQL como
valor. Ejemplo:
45
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
...
METHOD Area() RETURNS FLOAT
LANGUAGE PASCAL
PARAMETER STYLE GENERAL
...
La cláusula <deterministic characteristic> indica si el método es
determinista o no. Un método es determinista, si en cada llamada con los
mismos
parámetros
entrega
el
mismo
resultado,
por
ejemplo,
...Math.sqrt(9). Es difícil que un método de instancia sea determinista,
puesto que el estado actual del objeto, afecta su comportamiento, este
comportamiento es más propio de los métodos estáticos.
El valor por
defecto de esta cláusla es NOT DETERMINISTIC.
...
METHOD Area() RETURNS FLOAT
LANGUAGE PASCAL
PARAMETER STYLE GENERAL
NOT DETERMINISTIC
...
La cláusula <SQL-data access indication>, indica si el método manipula o
no datos y sentencias de SQL.
Los valores posibles son:
NO SQL,
CONTAINS SQL, READS SQL DATA, MODIFIES SQL DATA. Ejemplo:
...
METHOD Area() RETURNS FLOAT
LANGUAGE PASCAL
PARAMETER STYLE GENERAL
NOT DETERMINISTIC
NOT SQL
...
Los métodos que modifican datos de SQL (cláusula MODIFIES SQL DATA)
no son permitidos en:
•
Constraint
•
Assertions
•
Sentencia CASE
•
Before Triggers
•
Cláusula de búsqueda en sentencias DELETE
•
Cláusula de búsqueda en sentencias UPDATE (aunque es permitido
dentro de la cláusula SET)
•
Expresiones de consulta distintas a constructores de tablas.
46
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
La cláusula <null-call clause>, indica la forma de proceder, si todos los
parámetros pasados al momento de la llamada son nulos. Para este caso
existen dos alternativas, retornar NULL sin llamar al método (RETURNS
NULL ON NULL INPUT) o llamar al método (CALLED ON NULL INPUT). El
valor por defecto es CALLED ON NULL INPUT. Ejemplo:
...
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
RETURNS NULL ON NULL INPUT
...
4.2.1.3.2 Métodos estático
Los métodos estáticos, son aquellos que serán invocados a partir de un
tipo estructurado y no de un objeto.
Para definirlos se anteponen las
palabras reservadas STATIC METHOD seguido del nombre, la lista de
parámetros (que puede estar vacía) y opcionalmente el tipo del valor de
retorno. Un método estático, no posee el parámetro implícito self, porque
son invocados a partir de un tipo y no de un objeto. Por esta razón, no
podemos acceder a los atributos del tipo, desde un método estático.
Al igual que en un método de instancia, los métodos estáticos pueden ser
sobrecargados.
Por
ejemplo,
consideremos
el
mismo
tipo
triángulo
mostrado
anteriormente, agregándole un método estático que permita crear un
triángulo a partir de tres puntos:
CREATE TYPE triangulo AS
(
A punto ,
B punto ,
C punto
)INSTANTIABLE NOT FINAL
METHOD Area() RETURNS FLOAT,
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
STATIC METHOD crear(a Punto, b Punto, c Punto) RETURNS
triangulo
Para invocar al método crear se utiliza:
...triangulo::crear(a,b,c)
considerando que a,b,c son instancias del tipo Punto previamente
definidas.
47
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Al igual que en los métodos de instancia, podemos especificar las
características opcionales descritas en <method characteristic> en A.2.1.
4.2.1.3.3 Constructores
Cuando creamos un tipo estructurado con la cláusula INSTANTIABLE, el
sistema define un método constructor por defecto [25]. Este método, es
una función cuyo nombre coincide con el del tipo estructurado, no posee
argumentos, y el valor de retorno es una instancia del tipo al que
pertenece, donde el valor de cada atributo corresponde al valor por
defecto, especificado al momento de su creación.
Por ejemplo, para el
tipo persona, el constructor por defecto es persona( ).
El estándar SQL:1999, no permite los constructores definidos por el
usuario, pero el borrador de trabajo de la futura versión
del estándar
(SQL:200n), ya lo incorpora.
Existe un operador llamado NEW que nos permite invocar a un método de
instancia que haga las veces de constructor.
El método debe tener el
mismo nombre que su tipo estructurado, y puede ser sobrecargado.
Por
ejemplo, consideremos el siguiente tipo persona:
CREATE TYPE persona AS
(
rut
CHAR(12),
nombre
CHAR(40),
)INSTANTIABLE NOT FINAL
METHOD persona(r CHAR(12),n CHAR(40)) RETURNS persona
Si queremos construir un objeto del tipo persona utilizando el operador
NEW sería:
...new persona(’13.131.344-6’,’Miguel Romero Vásquez’)
El operador NEW suple la limitación de constructores definidos por el
usuario.
4.2.1.3.4 Creación de métodos (CREATE METHOD)
Para cada método definido en el tipo estructurado, es necesario definir su
código o enlazarlo con un programa externo.
Para esto utilizamos la
48
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
sentencia CREATE METHOD (ver A.2.4).
Por ejemplo, consideremos la
siguiente implementación de un número complejo:
CREATE TYPE complex AS
(
rpart REAL DEFAULT 0,
ipart REAL DEFAULT 0
)INSTANTIABLE FINAL
METHOD suma(x complex) RETURNS complex,
METHOD resta(x complex) RETURNS complex,
METHOD mult(x complex) RETURNS complex,
METHOD div(x complex) RETURNS complex;
Un numero complejo consta de dos partes una real (atributo rpart) y otra
imaginaria (atributo ipart), ambas dentro del rango de los números reales.
Además existen una serie de operaciones matemáticas que se pueden
aplicar a dichos números (métodos suma, resta, mult y div).
Para crear los método del tipo utilizando SQL/PSM, sería:
CREATE METHOD suma(x complex) RETURNS complex FOR complex
BEGIN
DECLARE co complex;
SET co = complex();
SET co.rpart = self.rpart + x.rpart;
SET co.ipart = self.ipart + x.ipart;
RETURN co;
END;
CREATE METHOD resta(x complex) RETURNS complex FOR complex
BEGIN
DECLARE co complex;
SET co = complex();
SET co.rpart = self.rpart - x.rpart;
SET co.ipart = self.ipart - x.ipart;
RETURN co;
END;
CREATE METHOD mult(x complex) RETURNS complex FOR complex
BEGIN
DECLARE co complex;
SET co = complex();
SET co.rpart = rpart * x.rpart – ipart * x.ipart;
SET co.ipart = rpart * x.ipart + ipart * x.rpart;
RETURN co;
END;
CREATE METHOD div(x complex) RETURNS complex FOR complex
BEGIN
DECLARE z REAL;
DECLARE co complex;
SET z = x.rpart * x.rpart + x.ipart * x.ipart;
SET co = complex();
SET co.rpart = (rpart * x.rpart + ipart * x.ipart)/z;
SET co.ipart = (ipart * x.rpart - rpart * x.ipart)/z;
49
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
RETURN co;
END;
Como puede observar, la sintaxis es bastante sencilla.
Parte con las
palabras reservadas CREATE METHOD, seguida por el nombre del
método,
la lista de argumentos y opcionalmente la cláusula RETURNS
junto al tipo del valor de retorno. La palabra reservada FOR nos permite
indicar el tipo al que pertenece el método, en este caso complex. A este
encabezado le sigue el cuerpo del método, que puede ser escrito en SQL
(como en el ejemplo anterior) o en un lenguaje externo (C, Fortran, Ada,
etc).
Para aquellos métodos que son implementados en un lenguaje
externo, es necesario indicar <external routine name>,<parameter style
clause>,<external security clause> (ver A.2.4). Por ejemplo: Consideremos
el mismo tipo complex, con el método suma externo. Lo primero sería
indicar el lenguaje en el que está programado al momento de definir el
tipo:
CREATE TYPE complex AS
(
rpart REAL DEFAULT 0,
ipart REAL DEFAULT 0
)INSTANTIABLE FINAL
METHOD suma(x complex) RETURNS complex,
LANGUAGE C
METHOD resta(x complex) RETURNS complex,
METHOD mult(x complex) RETURNS complex,
METHOD div(x complex) RETURNS complex;
Luego, al implementar el método, indicar el nombre externo, y
opcionalmente, el estilo del paso de
parámetros y la cláusula de
seguridad :
CREATE METHOD suma(x complex) RETURNS complex FOR complex
EXTERNAL NAME ‘/routines/suma’
PARAMETER STYLE GENERAL
EXTERNAL SECURITY INVOKER
Para poder invocar un método, el usuario debe tener el privilegio EXECUTE
sobre el método (otorgado con la cláusula GRANT).
La cláusula de seguridad indica al sistema qué privilegios considerar para
permitir o negar la ejecución del método, como también, cada una de sus
sentencias. Puede asumir tres valores posibles [46]:
50
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
•
EXTERNAL SECURITY DEFINER.
Considerar los privilegios del
usuario que definió el método.
•
EXTERNAL SECURITY INVOKER.
Considerar los privilegios del
usuario que invoca al método.
•
EXTERNAL SECURITY IMPLEMENTATION DEFINED.
Permite que la
implementación decida qué privilegios utiliza, si los del usuario que
definió el método o del que lo invoca. Este valor es asumido cuando
se omite la cláusula de seguridad.
Los métodos externos tienen varias ventajas frente a los métodos
implementados con SQL [46]:
•
Permiten utilizar funciones que ya teníamos, o incorporar bibliotecas
de funciones de otros lenguajes como Java, Pascal, C, Fortran,
extendiendo las capacidades de SQL, sin la necesidad de programarlas
en SQL.
•
Las rutinas externas son más portables (por ejemplo rutinas escritas
en C o Java).
•
Las rutinas externas, permiten aprovechar las características y
capacidades de un amplio conjunto de lenguajes.
concurrencia,
funciones
matemáticas
y
Por ejemplo:
estadísticas
avanzadas,
comunicación entre procesos, envío de correo electrónico, manejo de
censores, etc.
•
Las rutinas externas permiten invocar las mismas funciones que
utiliza el resto de nuestra aplicación, desde la base de datos.
•
Las
rutinas
externas
permiten
definir
la
cláusula
EXTERNAL
SECURITY.
Pero tienen las siguientes desventajas que deben ser consideradas [46]:
•
Mover datos entre la rutina externa y el código SQL requiere un
esfuerzo adicional de programación y a veces problemas, por la falta
de correspondencia entre los tipos de datos. Por ejemplo el tipo Real
de SQL soporta valores nulos, pero el tipo Real de C, no.
•
Para las rutinas externas que contienen código SQL, es necesaria la
creación de nuevas sesiones de SQL, lo que puede ser bastante
costoso.
51
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
•
El tiempo de desarrollo puede incrementarse al tener que utilizar
lenguajes externos, por el esfuerzo adicional de entrenamiento y
depuración frente a los métodos desarrollados bajo SQL/PSM.
4.2.1.4 Modificación de tipos (ALTER TYPE)
Con el predicado ALTER TYPE (ver A.2.3 <alter type statement>) podemos
agregar o eliminar atributos y métodos a un tipo estructurado.
Para
ejemplificarlo utilizaremos el siguiente tipo:
CREATE TYPE empleado AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldoBase INTEGER ,
anticipo
INTEGER DEFAULT 0,
fecha_ing DATE
DEFAULT CURRENT_DATE,
domicilio direccion
)INSTANTIABLE NOT FINAL
4.2.1.4.1 Agregar un atributo
Si queremos agregar el atributo email al tipo empleado, sería:
ALTER TYPE empleado ADD ATTRIBUTE email CHAR(50)
No podremos agregar el atributo email si existe una o más columnas en
alguna tabla relacional cuyo tipo de datos sea:
•
Empleado.
•
Un arreglo de cualquier supertipo o subtipo de empleado.
•
Cualquier supertipo o subtipo de T, siendo T un tipo que posee
uno o más atributos que referencian a un empleado.
•
Un arreglo de cualquier supertipo o subtipo de T, siendo T un tipo
que posee uno o más atributos que referencian a un empleado.
Tampoco podremos agregar un atributo, si existe alguna tabla de objetos
(ver 4.2.5.1 ) cuyo tipo base sea un subtipo (directo o no) de empleado.
La definición de un atributo con ALTER TYPE utiliza la misma sintaxis que
en CREATE TYPE.
52
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.2.1.4.2 Eliminar un atributo
Si queremos eliminar el atributo domicilio del tipo empleado sería:
ALTER TYPE empleado DROP ATTRIBUTE domicilio RESTRICT
En los siguientes casos, no podremos eliminar el atributo domicilio:
•
Si es el único que posee el tipo empleado.
•
Si es un atributo heredado.
•
Si existe una o más columnas en alguna tabla relacional cuyo tipo
de datos sea:
o
Empleado.
o
Un arreglo de cualquier supertipo o subtipo de empleado,
sea directo o no.
o
Cualquier supertipo o subtipo de T, sea directo o no.
Siendo T un tipo que posee uno o más atributos que
referencian a un empleado.
o
Un arreglo de cualquier supertipo o subtipo de T, sea
directo o no.
Siendo T un tipo que posee uno o más
atributos que referencian a un empleado.
•
Si existe alguna typed table (ver 4.2.5.1 ) cuyo tipo base sea un
subtipo (directo o no) de empleado.
•
•
Si es utilizado directa o indirectamente en:
o
El cuerpo de un método, una función o un procedimiento,
o
un trigger,
o
la expresión booleana de una constraint o una assertion
o
la expresión de consulta que define una vista.
Si es utilizado en una función de conversión definida por el usuario
(ver 4.2.1.7 )
4.2.1.4.3 Agregar un método
Si queremos agregar el método SueldoLiquido() al tipo empleado, sería:
ALTER TYPE empleado ADD
METHOD SueldoLiquido() RETURNS INTEGER
53
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Para especificar el nuevo método, utilizamos la misma sintaxis que en
CREATE TYPE.
4.2.1.4.4 Eliminar un método
Consideremos el siguiente tipo:
CREATE TYPE triangulo AS
(
A punto ,
B punto ,
C punto
)INSTANTIABLE NOT FINAL
METHOD Area() RETURNS FLOAT,
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
INSTANCE METHOD distanciaA(x FLOAT,y FLOAT) RETURNS FLOAT
Si queremos eliminar el método distanciaA del tipo triangulo sería:
ALTER TYPE triangulo DROP
METHOD distanciaA(Punto) FOR triangulo RESTRICT
Para indicar el método a eliminar, tenemos que indicar
su nombre y
opcionalmente, los tipos de datos de los parámetros, separados por coma
y entre paréntesis, seguido de eso, la palabra reservada FOR y el nombre
del tipo al que pertenece.
Esto último, es obligatorio cuando tenemos
sobrecargado el método.
4.2.1.5 Eliminación de tipos (DROP TYPE)
Mediante la sentencia DROP TYPE, podemos eliminar un tipo estructurado.
Por ejemplo, si queremos eliminar el tipo punto, decimos:
DROP TYPE punto CASCADE
La cláusula CASCADE, indica que se deben borrar todas las dependencias
que existan con este tipo. Alternativamente a CASCADE, existe la cláusula
RESTRICT, que impide el borrado del tipo si existen dependencias.
Por
ejemplo:
DROP TYPE punto RESTRICT
54
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.2.1.6 Comparación de instancias
Inicialmente, no podemos comparar dos instancias de un tipo estructurado
(ej: A>B) . Para lograr esto, es necesario que el usuario defina una función
que los compare y luego asociarla al tipo estructurado correspondiente. Para
esto existe la sentencia CREATE ORDERING (ver A.2.8).
Existen dos categorías de comparación:
•
EQUALS ONLY. Sólo se permiten comparaciones de igualdad (=)
y
desigualdad (<>).
•
ORDER FULL. Todas las comparaciones son permitidas (>,<,=,<>)
Además,
podemos
escoger
entre
tres
categorías
de
funciones
de
comparación:
•
STATE. La función de comparación es creada por el sistema. Dicha
función tiene dos parámetros (las instancias a comparar) y retorna un
Boolean. La función compara ambas instancias, atributo por atributo.
Si coinciden los valores de todos los atributos entre las instancias,
retorna true si no, false.
•
RELATIVE. El usuario debe especificar la función de comparación, la
cual debe contar con dos parámetros (las instancias a comparar) y
cuyo valor de retorno sea del tipo Integer. La función debe retornar 0
si ambas instancias son iguales, un valor positivo si la primera
instancia es mayor que la segunda, y un valor negativo si es menor.
•
MAP. El usuario debe especificar la función de comparación, la cual
debe contar con un sólo parámetro y debe retornar un tipo de dato
primitivo. La función no se encarga de comparar las instancias, sólo
indica la posición que tomaría la instancia pasada por parámetro, si
ordenáramos el universo completo de las instancias. El sistema utiliza
el valor devuelto para realizar la comparación.
Al momento de definir una función de comparación debemos considerar lo
siguiente:
•
STATE sólo puede ser utilizado con EQUALS ONLY.
55
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
•
dentro de una jerarquía de tipos, STATE
y RELATIVE deben ser
especificados para el supertipo máximo (aquel que no tiene padre).
•
MAP puede ser especificado para más de un tipo, dentro de una
jerarquía de tipos, pero todos ellos deben utilizar MAP, es decir, no
podemos definir unos tipos con MAP y otros con STATE o RELATIVE.
Para
ejemplificarlo,
utilizaremos
el
mismo
tipo
empleado
utilizado
anteriormente:
CREATE TYPE empleado AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldoBase INTEGER ,
anticipo
INTEGER DEFAULT 0,
fecha_ing DATE
DEFAULT CURRENT_DATE,
domicilio direccion
)INSTANTIABLE NOT FINAL
Si queremos definir una función de comparación del tipo STATE sería:
CREATE ORDERING FOR empleado
EQUALS ONLY BY STATE
Con ella podremos hacer comparaciones de igualdad y desigualdad. Si lo que
queremos es permitir todas las comparaciones, debemos utilizar ORDER
FULL y definir una función del tipo RELATIVE o MAP. Por ejemplo:
CREATE ORDERING FOR empleado
ORDER FULL BY RELATIVE
WITH FUNCTION empleado_relative(empleado,empleado)
CREATE ORDERING FOR empleado
ORDER FULL BY MAP
WITH FUNCTION empleado_map(empleado)
Una implementación válida de la función empleado_relative sería:
CREATE FUNCTION empleado_relative(a empleado, b empleado)
RETURNS INTEGER
BEGIN
DECLARE comp INTEGER;
IF a.sueldoBase = b.sueldoBase THEN
SET comp = 0;
ELSE
IF a.sueldoBase > b.sueldoBase THEN
SET comp = 1;
ELSE
SET comp = - 1;
END IF;
END IF;
RETURN comp;
END
56
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Una implementación válida de la función empleado_map sería:
CREATE FUNCTION empleado_map(a empleado) RETURNS INTEGER
BEGIN
RETURN a.sueldoBase;
END
Las funciones del tipo MAP y RELATIVE, también pueden ser usadas con
EQUALS ONLY. Por ejemplo:
CREATE ORDERING FOR empleado
EQUALS ONLY BY RELATIVE
WITH FUNCTION empleado_relative(empleado,empleado)
CREATE ORDERING FOR empleado
EQUALS ONLY BY MAP
WITH FUNCTION empleado_map(empleado)
Para entender mejor cómo trabajan estas funciones, consideremos la
comparación “E1 = E2” siendo E1 y E2 instancias del tipo empleado.
Internamente esta expresión será sustituida por otra, basada en la función de
comparación correspondiente. Tenemos tres casos posibles:
•
Si la función es del tipo STATE, la expresión se sustituye por:
o
“SF(E1,E2)=TRUE”, siendo SF(...) la función definida por el
sistema.
•
Si la función es del tipo MAP, se sustituye por:
o
•
“empleado_map(E1) = empleado_map(E2)”
Si la función es del tipo RELATIVE, se sustituye por:
o
“empleado_relative(E1,E2) = 0”
4.2.1.6.1 Eliminación de funciones de comparación
Para eliminar la función de comparación de un tipo, utilizamos la sentencia
DROP ORDERING (ver A.2.9).
Por ejemplo, para eliminarla del tipo
empleado sería:
DROP ORDERING FOR empleado RESTRICT
No podremos eliminar la función de comparación, si existe algún
predicado que compare instancias del tipo empleado en:
•
métodos , Funciones o procedimientos
•
Vistas
•
Constraint
57
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
•
Assertion
•
Trigger
4.2.1.7 Conversión de UDT (CAST definidos por el usuario)
SQL siempre ha sido un lenguaje fuertemente tipado. Esto significa que no
podemos mezclar tipos arbitrariamente en expresiones de comparación o en
asignaciones, sino que debemos hacer una conversión explícita de tipos con
la sentencia CAST. Para los tipos primitivos (ej.: INTEGER, BOLEAN, CHAR,
etc), existen funciones CAST predefinidas. Por ejemplo, si queremos asignar
un valor INTEGER a una variable SMALLINT dentro de una función sería:
...
DECLARE a INTEGER, b SMALLINT;
SET b = CAST (a AS SMALLINT);
...
Para los tipos definidos por el usuario, no existen funciones CAST por
defecto. Para solucionar esto, SQL-1999 permite al usuario definir funciones
CAST para sus tipos con la sentencia CREATE CAST (ver A.2.6). Por ejemplo,
consideremos que tenemos dos tipos estructurados, uno llamado T1 y otro
T2, y queremos implementar un CAST para convertir valores de T1 a T2.
Lo primero que tenemos que hacer, es crear una función con un único
parámetro del tipo T1, cuyo valor de retorno sea del tipo T2, es decir:
CREATE FUNCTION conver(a T1) RETURNS T2
BEGIN
...
RETURN ...
END;
Y luego definimos el CAST de la siguiente manera:
CREATE CAST(T1 AS T2) WITH FUNCTION convert(T1) AS ASSIGNMENT
La cláusula AS ASSIGNMENT es opcional, y permite que la función de
conversión sea llamada implícitamente en las asignaciones. Por ejemplo:
...
DECLARE a T1, b T2;
SET b = a;
...
Si omitimos esta cláusula, tendremos que llamar explícitamente al CAST en
las asignaciones. Por ejemplo:
...
58
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
DECLARE a T1, b T2;
SET b = CAST (a AS T2);
...
4.2.1.7.1 Eliminación de CAST definidos por el usuario
Para eliminar un CAST definido por el usuario existe la sentencia DROP
CAST ( ver A.2.7). Por ejemplo:
DROP CAST (T1 AS T2) RESTRICT
No podremos eliminar el CAST definido por el usuario, si es utilizado en:
•
métodos , Funciones o procedimientos
•
Vistas
•
Constraint
•
Assertion
•
Trigger
4.2.2 Colecciones
Una colección es una estructura que permite almacenar cero o más
elementos de distinto o del mismo tipo de datos [26]. El término colección es
genérico, y comprende varios tipos de colecciones como: arreglos, conjuntos,
árboles, etc. El estándar SQL:1999 solamente soporta los arreglos.
4.2.2.1 Arreglos
Un arreglo (array) es un conjunto de elementos del mismo tipo, donde cada
elemento está en una posición determinada [31]. Al definir un arreglo, se
especifica la cantidad máxima de elementos que puede tener (m en adelante).
Las posiciones del arreglo comienzan a partir de 1 (uno), hasta n, siendo n el
número de elementos que contiene el arreglo, que debe estar en el rango
1≤n≤m.
Un arreglo, es un tipo de datos, que lo utilizamos de igual modo que un tipo
primitivo. Por ejemplo, podemos crear un tipo polígono, que contenga un
arreglo para sus vértices (del tipo punto), y los métodos de area(), y
perímetro(), de la siguiente manera:
59
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
CREATE TYPE poligono
(
vertices punto ARRAY [200]
)INSTANTIABLE NOT FINAL
METHOD Area() RETURN FLOAT,
METHOD Perimetro() RETURN FLOAT
Si queremos acceder al segundo vértice del poligono p, se escribe:
...p.vertices[2].
Podemos asignar varios elementos en un arreglo, simultáneamente.
Por
ejemplo, supongamos que hemos definido un arreglo notas, y quisiéramos
asignarle las calificaciones: 100, 80 y 45 de una sola vez, esto sería:
...
set Notas = ARRAY[100,80,45];
...
También existe un operador de concatenación (||), que nos permitirá construir
un nuevo arreglo, a partir de dos o más. Para el mismo ejemplo anterior,
pensemos que queremos agregar las notas al final del arreglo, esto sería:
...
set Notas = Notas || ARRAY[100,80,45];
...
Podemos definir un arreglo a partir de cualquier tipo de datos, sea primitivo o
no, siempre y cuando, no contenga o no sea un arreglo.
Dos arreglos (C y D) son iguales (C = D), si ambos tienen el mismo número
de elementos y C[i]=D[i], para i=1 hasta n
4.2.3 Encapsulamiento
Como vimos en la sección 2.2.3, el encapsulamiento abarca tres aspectos:
•
Agrupar atributos y métodos en una sola entidad.
•
Distinguir entre interfaz(pública) e implementación (privada)
•
Asignar niveles de acceso individual a los atributos y métodos.
El primer aspecto, es cubierto con el predicado CREATE TYPE. Esta es la
parte pública del método.
60
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Con el predicado CREATE METHOD es cubierto el segundo punto. Gracias a
esta
división
(publica
y
privada)
podemos
realizar
cambios
a
la
implementación de los métodos, sin que estos afecten a las aplicaciones que
los utilizan.
El tercer punto es cubierto medianamente por las funciones observadoras y
mutadoras (ver 4.2.1.2 ) definidas por el sistema, puesto que estas impiden
que los usuarios accedan a los atributos directamente. Lamentablemente, no
podemos sobrescribir dichas funciones.
Lo que falta para que el soporte al encapsulamiento sea completo, es la
posibilidad de definir niveles de acceso a los atributos y métodos, como
public, private y protected de Java.
Sin embargo, el modelo de seguridad de SQL-1999, permite obtener una
funcionalidad similar, pero no completa de lo anterior.
Con respecto a los
métodos, sólo los usuarios que tenga el privilegio EXECUTE podrán ejecutar
un método, tanto para objetos persistentes como transitorios. Para otorgar
el privilegio EXECUTE utilizamos la sentencia GRANT. Por ejemplo:
GRANT EXECUTE ON METHOD sueldo_liquido() FOR empleado TO
PUBLIC
Podemos ejecutar métodos dentro de sentencias SELECT. Para ello debemos
otorgar el permiso correspondiente. Por ejemplo:
GRANT SELECT (METHOD sueldo_liquido() FOR empleado) ON TABLE
tbl_emp TO PUBLIC
Con respecto a los atributos, sólo podremos restringir el acceso a ellos sobre
objetos persistentes, para los objetos transitorios, todos sus atributos serán
públicos. Por defecto, un usuario no puede acceder a las filas de una tabla.
Existen distintas sentencias que manipulan una tabla, para cada una de ellas
existe un privilegio que debe ser otorgado. Por ejemplo:
GRANT SELECT (rut,nombre,sueldo) ON TABLE tbl_emp TO PUBLIC
GRANT INSERT (rut,nombre,sueldo) ON TABLE tbl_emp TO PUBLIC
GRANT UPDATE (rut,nombre) ON TABLE tbl_emp TO PUBLIC
GRANT DELETE ON TABLE tbl_emp TO PUBLIC
61
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
También podemos restringir el acceso de los atributos, creando vistas sobre
las tablas.
4.2.4 Modularidad
SQL:1999 cuenta con la noción de módulos, pero estos sólo proveen
modularidad para las funciones y procedimientos almacenados, pero no para
tipos. Sin embargo, podemos agrupar tipos basándonos en los esquemas de
SQL, logrando así una funcionalidad similar.
4.2.5 Persistencia
Para hacer persistir los objetos tenemos dos alternativas:
•
Almacenarlos como columnas en tablas relacionales
•
Almacenarlos en una tabla especial denominada typed table, donde
cada fila es un objeto y cada columna un atributo del mismo.
En las siguientes secciones veremos el manejo de tablas que almacenen
objetos, tanto en columnas como en fila.
Además de cómo trabajar con
dichas instancias.
4.2.5.1 Manejo de Tablas
El estándar incorpora varias características a las tablas relacionales. Además
de permitir almacenar objetos como columnas, define tres tipos especiales de
tablas: typed tables, subtablas y supertablas.
En la presente sección,
describiremos como definir dichas tablas.
4.2.5.1.1 Creación (CREATE TABLE)
Como mencionamos anteriormente, podemos almacenar objetos como
columnas de tablas relacionales. Por ejemplo, Consideremos la siguiente
definición de un tipo direccion.
62
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
CREATE TYPE Direccion AS
(
calle
CHAR(40),
numero
CHAR(10),
ciudad
CHAR(30),
region
CHAR(30)
)NOT FINAL
Ahora, podemos crear una tabla relacional con una columna del tipo
dirección.
Como ejemplo, consideremos la definición de una tabla de
personas de la siguiente manera:
CREATE TABLE persona
(
rut
CHAR(12) PRIMARY KEY,
nombre
CHAR(40),
fecha_nacim DATE,
domicilio
direccion
)
Como podemos observar, es bastante sencillo definir columnas basadas
en tipos estructurados.
Los objetos almacenados como columnas no pueden ser referenciados por
no poseer un OID. Solamente los objetos almacenados en una typed table
pueden ser referenciados.
Una typed table, es una tabla o vista construida
en base a un tipo
estructurado definido por el usuario. Para cada atributo del tipo base, es
creada una columna con el mismo nombre y el mismo tipo de datos.
Además de estas, se agrega otra, para almacenar el identificador de
objeto.
Esta columna tiene las restricciones UNIQUE y NOT NULL
implícitas.
Para ejemplificarlo consideremos el tipo empleado utilizado en secciones
anteriores:
CREATE TYPE empleado AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldoBase INTEGER ,
anticipo
INTEGER DEFAULT 0,
fecha_ing DATE
DEFAULT CURRENT_DATE,
domicilio direccion
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
METHOD SueldoLiquido() RETURNS INTEGER
63
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Para crear una typed table llamada tbl_emp basada en el tipo empleado
sería:
CREATE TABLE tbl_emp OF empleado
(REF IS oid SYSTEM GENERATED)
oid, es el nombre de la columna adicional que almacenará el identificador
de objeto.
identificador
El nombre es puesto por el usuario y puede ser cualquier
válido
de
columna.
El
tipo
de
datos
de
oid
es
REF(empleado), este no puede ser asignado por el usuario.
Dependiendo de la forma que el tipo base de la tabla maneje las
referencias, (SYSTEM GENERATED, USER GENERATED y DERIVED) se
especificará:
•
REF IS oid SYSTEM GENERATED
•
REF IS oid USER GENERATED
•
REF IS oid DERIVED
El valor que asumirá la columna oid, será asignado al insertar el objeto en
la tabla, y no podrá ser modificado posteriormente.
Si especificamos
SYSTEM GENERATED o DERIVED, el valor de oid será definido
automáticamente al momento de la inserción.
En cambio, si es USER
GENERATED, será entregado por el usuario.
Si queremos hacer persistir objetos que tengan un supertipo (ver 4.2.6.3 ),
tenemos la posibilidad de definir una estructura super tabla/subtabla.
Por ejemplo, consideremos el tipo vendedor que es un subtipo de
empleado definido de la siguiente manera:
CREATE TYPE vendedor UNDER empleado AS
(
comision
FLOAT,
viatico
INTEGER
)INSTANTIABLE NOT FINAL
OVERRIDING METHOD SueldoLiquido() RETURNS INTEGER
Ahora, podemos crear una subtabla de tbl_emp que almacene instancias
del tipo vendedor. Para ello escribimos:
CREATE TABLE tbl_vendedor OF vendedor UNDER tbl_emp
64
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Para que esta sentencia sea válida, tbl_emp, debe ser una typed table
cuyo tipo de datos sea el supertipo directo de vendedor. Si observamos la
definición
hecha
de
tbl_emp
anteriormente,
veremos
que
estas
condiciones se cumplen.
En las subtablas, no podemos especificar la cláusula <self-referencing
column specification>, esta es heredada de la supertabla. Las columnas
de la supertabla, no son heredadas físicamente en la subtabla, pero si
referenciadas.
Como toda instancia de un subtipo, lo es también de su supertipo, cada
objeto almacenado en una subtabla, también es almacenado en la
supertabla.
Debido a esto, físicamente, los valores de los atributos
heredados de una instancia, serán almacenados en la supertabla y los
valores más específicos del tipo, serán almacenados en la subtabla. Como
es el mismo objeto almacenado en la supertabla y en la subtabla, poseerá
el mismo OID en ambas. Es por esto que la forma de manejar el OID debe
concordar en toda la Jerarquía de tablas.
Cuando necesitamos recuperar un objeto en particular, el sistema se
encarga
de
recopilar
los
valores
desde
las
distintas
tablas,
automáticamente.
La definición de estructuras jerárquicas de tablas, permite minimizar el
impacto al extender las aplicaciones.
Al definimos tablas relacionales, podemos especificar restricciones como
NOT NULL,
CHECK, PRIMARY KEY, sobre ellas.
En las typed tables,
estas restricciones también son permitidas, a excepción de PRIMARY KEY.
Por ejemplo, si queremos restringir el atributo comisión a valores entre 0 y
100, seria:
CREATE TABLE tbl_vendedor OF vendedor UNDER tbl_emp
(CONSTRAINT com CHECK (comision BETWEEN 0 AND 100))
4.2.5.1.2 Modificación (ALTER TABLE)
65
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Para modificar una tabla utilizamos el predicado ALTER TABLE (A.2.13).
Esta sentencia nos permite:
•
Agregar y Eliminar columnas.
•
Agregar y elimina cláusula DEFAULT.
•
Agregar y eliminar cláusula SCOPE.
•
Agregar y eliminar restricciones (CONSTRAINT).
Para la eliminación de elementos podemos especificar la cláusula
CASCADE, que indica al sistema que, además de eliminar el elemento,
elimine todas las dependencias existentes; o la cláusula RESTRIC, que
impide el borrado del elemento al haber dependencias.
Por ejemplo, si queremos eliminar la restricción com de la tabla
tbl_vendedor sería:
ALTER TABLE tbl_vendedor DROP CONSTRAINT com CASCADE
Existen limitaciones a la hora de utilizar esta sentencia. Estas son:
•
No podremos agregar o eliminar columnas a una typed table
•
No podremos agregar o eliminar las cláusulas DEFAULT o SCOPE a
una columna heredada en una subtabla.
•
No podremos agregar o eliminar las cláusulas DEFAULT o SCOPE a
la columna que almacena el identificador de objeto.
4.2.5.1.3 Eliminación (DROP TABLE)
Para eliminar una tabla utilizamos el predicado DROP TABLE (ver A.2.14).
Cuando queremos eliminar una tabla, debemos indicarle al sistema qué
hacer con las dependencias que existan de ella, como pueden ser,
subtablas, triggers, vistas, etc. Para ello tenemos dos predicados:
•
CASCADE, que indica que se borren todas las dependencias de la
tabla.
•
RESTRICT, impide que se borre la tabla si existen dependencias.
La sintaxis es bastante sencilla. Por ejemplo, si queremos eliminar la tabla
tbl_emp, sería:
DROP TABLE tbl_emp CASCADE
O bien:
DROP TABLE tbl_emp RESTRICT
66
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.2.5.2 Manejo de Instancias
Para manipular las instancias que fueron almacenadas en una tabla,
utilizamos las mismas sentencias del manejo de filas y columnas en tablas
relacionales.
Las operaciones sobre las instancias las podemos agrupar en: Inserción,
selección, eliminación y modificación de objetos. Estas operaciones serán
descritas en las secciones siguientes.
4.2.5.2.1 Inserción de objetos
Para insertar un objeto, tanto en tablas relacionales como en typed table
utilizamos la sentencia INSERT INTO (ver A.2.15). Veamos primero cómo
insertar un objeto como columna de una tabla relacional.
Para ello,
consideremos las siguientes definiciones:
CREATE TYPE direccion AS
(
calle
CHAR(40),
numero
CHAR(10),
ciudad
CHAR(30)
)NOT FINAL
METHOD direccion(ca CHAR(40),nu CHAR(10),ciu CHAR(30))
RETURNS direccion
CREATE TABLE persona
(
rut
CHAR(12) PRIMARY KEY,
nombre
CHAR(40),
domicilio
direccion
)
La inserción de una fila en la tabla persona sería:
INSERT INTO persona
VALUES(‘13131344-6’,’Miguel Romero’,
NEW direccion(‘Emmanuel, pasaje san Damián’,
’1661’,’Chillán’)
)
Mediante el operador NEW creamos un nuevo objeto del tipo direccion, el
cual será asignado a la columna domicilio de la tabla persona. También
podremos utilizar el constructor del tipo direccion, el que creará un objeto
con los valores por defecto. Esta inserción sería:
67
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
INSERT INTO persona
VALUES(‘13131344-6’,’Miguel Romero’,direccion())
La sintaxis para insertar un objeto como fila es muy similar. Por ejemplo,
consideremos un tipo cliente y una tabla de clientes (tbl_cli), definidos de
la siguiente manera:
CREATE TYPE cliente AS
(
rut
CHAR(12),
nombre
CHAR(40),
domicilio direccion
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
CREATE TABLE tbl_cli OF cliente
(REF IS oid SYSTEM GENERATED)
Para insertar un cliente en esta tabla sería:
INSERT INTO tbl_cli
VALUES(‘13131344-6’,’Miguel Romero’,
NEW direccion(‘Emmanuel, pasaje san Damián’,
’1661’,’Chillán’)
)
al insertar este objeto, automáticamente se genera el valor para la
columna OID, puesto que esta columna fue definida como SYSTEM
GENERATED.
Al momento de insertar, tenemos la posibilidad de sobrescribir el valor
que el sistema asigna automáticamente como OID. Por ejemplo
INSERT INTO tbl_cli (oid,rut,nombre,domicilio)
OVERRIDING SYSTEM VALUE
VALUES(145,‘13131344-6’,’Miguel Romero’,
NEW dirección(‘Emmanuel, pasaje san Damián’,
’1661’,’Chillán’)
)
Si al definir la tabla, especificamos que la columna es generada por el
usuario, obligatoriamente tendremos que entregar el valor para la columna
OID. Por ejemplo, consideremos la cláusula REF del tipo cliente como:
...
REF USING NUMERIC(8)
y la definición de la tabla como:
CREATE TABLE tbl_cli OF cliente
(REF IS oid USER GENERATED)
68
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
La inserción de un cliente sería:
INSERT INTO tbl_cli (oid,rut,nombre,domicilio)
VALUES(13131344,‘13131344-6’,’Miguel Romero’,
NEW dirección(‘Emmanuel, pasaje san Damián’,
’1661’,’Chillán’)
)
Para insertar un objeto en una typed table, el tipo estructurado base de la
tabla, debe ser instanciable (INSTANTIABLE).
Cuando insertamos un objeto en una typed table que posea una
supertabla, automáticamente se insertará la fila correspondiente en la
supertabla, con los valores para los atributos heredados. Para ello, será
necesario que asignemos los valores tanto para los atributos heredados
como para los más específicos, dentro del predicado INSERT.
Por
ejemplo, para insertar un vendedor en la tabla tbl_vendedor definida en la
sección 4.2.5.1.1 sería:
INSERT INTO tbl_vendedor (rut,nombre,SueldoBase,
Anticipo, domicilio, comision, viatico)
VALUES(’11.111.111-1’,’Luis Perez’,150000,10000,
direccion(),12,35000)
Si se excluyen valores para alguno de los atributos, estos asumirán el valor
por defecto. Eso es lo que pasa en el ejemplo anterior con el atributo
fecha_ing, que no fue especificado.
4.2.5.2.2 Selección de objetos (SELECT)
La
sentencia
SELECT,
nos
permite
obtener
uno
o
más
objetos
almacenados en tablas, tanto relacionales como typed table. Por ejemplo,
consideremos la tabla de persona definida en la sección anterior (ver
4.2.5.2.1 ), supongamos que queremos obtener el nombre y el domicilio
de todas las personas que viven en Chillán, esto sería:
SELECT nombre, domicilio.calle, domicilio.numero
FROM persona
WHERE domicilio.ciudad=’Chillán’
Como puede observar, podemos utilizar el atributo de un objeto, de la
misma manera que las columnas de las tablas relacionales.
pasa con los métodos.
Lo mismo
Por ejemplo, consideremos la tabla tbl_emp
69
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
definida en la sección
4.2.5.1.1 donde el tipo base es empleado.
Si
queremos obtener el RUT, el nombre y el sueldo líquido de todos los
empleados que tengan sueldos superiores a $250.000, sería:
SELECT e.rut,e.nombre,e.SueldoLiquido()
FROM tbl_emp e
WHERE e.SueldoLiquido() > 250000
Si aplicamos la sentencia SELECT sobre una typed table que posea
subtablas, la búsqueda de filas se extenderá a todas las subtablas que
posea.
Por ejemplo, consideremos la tabla tbl_vendedor que es una
subtabla de tbl_emp y cuyo tipo base es vendedor (vea 4.2.5.1.1 ). Para
obtener a todos los empleados de la empresa, incluyendo a los
vendedores, sería:
SELECT e.rut,e.nombre,e.SueldoLiquido()
FROM tbl_emp
Gracias al polimorfismo (ver
4.2.6.3 ), la
ejecución del método
SueldoLiquido(), dependerá del tipo concreto del objeto ya sea empleado
o vendedor. Para el ejemplo anterior, esta característica es fundamental,
pues el cálculo del sueldo líquido de un vendedor, es diferente al de un
empleado.
Para
excluir de la búsqueda a las subtablas de tbl_emp, utilizamos la
cláusula ONLY, de la siguiente manera:
SELECT *
FROM ONLY(tbl_emp)
También podemos restringir la búsqueda a la tabla tbl_vendedor, de la
siguiente manera:
SELECT *
FROM tbl_emp
WHERE DEREF(oid) IS OF(tbl_vendedor)
Cuando tenemos un atributo o una columna que es una referencia a un
objeto, podemos acceder a los atributos y métodos del objeto al que
referencia, utilizando el operador ->.
Por ejemplo, consideremos los
siguientes tipos y sus respectivas tablas:
CREATE TYPE punto AS
(
X
REAL,
Y
REAL
70
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
CREATE TABLE tbl_pto OF punto
(REF IS oid SYSTEM GENERATED)
CREATE TYPE linea_recta AS
(
A
REF punto,
B
REF punto
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
CREATE TABLE tbl_lineas OF linea_recta
(REF IS oid SYSTEM GENERATED)
Si queremos obtener las coordenadas de los puntos A y B de todas las
líneas que tengan un largo mayor a 100, sería:
SELECT L.A->X, L.A->Y, L.B->X, L.B->Y
FROM tbl_lineas L
WHERE L.A->distanciaA(B) > 100
El uso de referencias simplifica el manejo de consultas, puesto que
disminuye la necesidad de utilizar JOIN.
4.2.5.2.3 Modificación de objetos
Para modificar uno o más objetos, utilizamos el predicado UPDATE (ver
A.2.16). Por ejemplo, consideremos la typed table tbl_emp definida en la
sección 4.2.5.1.1 donde el tipo base es empleado; si queremos aumentar
el sueldo en $25.000 a todos los empleados que tengan sueldos entre
$100.000 y $ 200.000, sería:
UPDATE tbl_emp
SET SueldoBase = SueldoBase + 25000
WHERE SueldoBase BETWEEN 100000 AND 200000
Si aplicamos el predicado UPDATE sobre una supertabla, los cambios
también se aplicarán a todos los objetos de las subtablas que cumplan con
la condición definida en la cláusula WHERE Para evitar esto, utilizamos el
predicado ONLY de la siguiente manera:
UPDATE ONLY(tbl_emp)
SET SueldoBase = SueldoBase + 25000
WHERE SueldoBase BETWEEN 100000 AND 200000
71
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Al igual que en la sentencia SELECT, en UPDATE, podemos restringir las
tablas que serán utilizadas. Si en el ejemplo anterior, quisiéramos que
UPDATE sólo afectara a la tabla tbl_vendedor sería:
UPDATE tbl_emp
SET SueldoBase = SueldoBase + 25000
WHERE DEREF(oid) IS OF(tbl_vendedor) AND SueldoBase
BETWEEN 100000 AND 200000
Como toda fila de la tabla tbl_vendedor posee una fila correspondiente a
sus atributos heredados en la tabla tbl_emp, el sistema ajustará
automáticamente la fila correspondiente a la supertabla cuando utilicemos
el predicado UPDATE sobre la tabla tbl_vendedor. Por ejemplo:
UPDATE tbl_vendedor
SET SueldoBase = SueldoBase + 25000
WHERE SueldoBase BETWEEN 100000 AND 200000
Si el tipo base de la tabla, posee un atributo que es un arreglo, podemos
actualizarlo de dos maneras.
La primera, tomando los elementos
individualmente, por ejemplo, consideremos que el tipo base posee un
atributo llamado arr que es un arreglo de 5 enteros:
UPDATE tabla_de_arreglos
SET arr[5] = 23, arr[2] = 12
WHERE arr[1]=0
Y la segunda, asignando un arreglo completo, por ejemplo:
UPDATE tabla_de_arreglos
SET arr = ARRAY[12,34,56,78,90]
WHERE arr[1]=0
4.2.5.2.4 Eliminación de objetos
Para eliminar uno o más objetos utilizamos el predicado DELETE
A.2.17).
(ver
Este predicado borrará todas las filas que cumplan con la
condición indicada por la cláusula WHERE, tanto en tablas relacionales
como en typed tables. Por ejemplo, consideremos la tabla tbl_cli definida
en la sección 4.2.5.2.1
Para eliminar a todos los clientes cuyo nombre
contenga el string ‘miguel’, sería:
DELETE FROM tbl_cli c WHERE c.nombre LIKE ’%miguel%’
72
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Si ejecutamos la sentencia DELETE sobre una typed table que posea
subtablas, también se eliminarán todos los objetos que cumplan con la
condición en las subtablas. Por ejemplo, consideremos la tabla tbl_emp
definida en la sección 4.2.5.1.1 que posee una subtabla denominada
tbl_vendedor, si ejecutamos la sentencia:
DELETE FROM tbl_emp e WHERE e.sueldobase < 100
Eliminará a todos los empleados y vendedores que tengan sueldos inferior
a 100. Para limitar el borrado a la tabla tbl_emp, utilizamos la cláusula
ONLY. Ejemplo:
DELETE FROM ONLY(tbl_emp) e WHERE e.sueldobase < 100
Al igual que en UPDATE, podemos restringir las tablas que serán
utilizadas por DELETE.
Si para el ejemplo anterior, queremos eliminar
solamente a los vendedores que cumplan con esa condición sería:
DELETE FROM tbl_emp e
WHERE DEREF(oid) IS OF(tbl_vendedor) AND
e.sueldobase < 100
Al eliminar directamente una fila de una subtabla, automáticamente se
eliminará la fila correspondiente en la supertabla. Por ejemplo:
DELETE FROM tbl_vendedor v
WHERE v.sueldobase < 100
4.2.6 Jerarquía de Clases
4.2.6.1 Asociación
Como mencionamos en la sección 2.2.5.2 , el concepto de asociación es
similar al de relación en el modelo entidad relación.
Por eso, podemos
utilizar las mismas estrategias para su implementación, pero con la ventaja
de la existencia de las referencias de objeto, que son más eficientes que el
manejo de clave foránea. Por ejemplo, consideremos la siguiente asociación:
Vende
Vendedor
1
Cliente
*
73
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Para implementarla, agregaremos un atributo en el tipo cliente que sea una
referencia al tipo vendedor. La implementación de los tipos quedaría:
CREATE TYPE vendedor AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldo
NUMBER,
comision
NUMBER,
domicilio
direccion
)INSTANTIABLE NOT FINAL
CREATE TYPE cliente AS
(
rut
CHAR(12),
nombre
CHAR(40),
telefono
CHAR(20),
domicilio
dirección,
vendedorAsignado REF(vendedor)
)INSTANTIABLE NOT FINAL
Otra alternativa es agregar un atributo clientes al tipo vendedor, que sea un
arreglo de referencias a sus clientes. El único inconveniente es que debemos
definir un largo máximo al arreglo. Lo anterior sería:
CREATE TYPE vendedor AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldo
NUMBER,
comision
NUMBER,
domicilio
direccion,
clientes
REF(cliente) ARR [100]
)INSTANTIABLE NOT FINAL
Si la multiplicidad de la asociación es
uno a uno, cualquiera de los tipos
puede tener la referencia al otro.
Si la multiplicidad de la asociación es Muchos a muchos, o la asociación en si
misma tenga atributos, será necesario crear un tipo para implementarla. Por
ejemplo, supongamos que la asociación entre un vendedor y un cliente fuera:
vende
Vendedor
*
Cliente
*
Cartera_de_clientes
74
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
La implementación de estos tres tipos sería:
CREATE TYPE vendedor AS
(
rut
CHAR(12),
nombre
CHAR(40),
sueldo
NUMBER,
comision
NUMBER,
domicilio
direccion
)INSTANTIABLE NOT FINAL
CREATE TYPE cliente AS
(
rut
CHAR(12),
nombre
CHAR(40),
telefono
CHAR(20),
domicilio
direccion
)INSTANTIABLE NOT FINAL
CREATE TYPE cartera_de_clientes AS
(
vendedorAsignado REF(vendedor),
cliente
REF(cliente)
)INSTANTIABLE NOT FINAL
4.2.6.2 Agregación y Composición
La implementación de la agregación es muy similar a la asociación. Pero se
diferencia por existir una relación todo-parte, donde desde el todo queremos
acceder a sus partes. En la Agregación, el todo no contiene físicamente a las
partes, por esta razón, la implementación es a través de referencias de
objetos.
Consideremos por ejemplo la relación de agregación entre una
carrera y sus asignaturas, donde una carrera puede tener muchas asignaturas
y una asignatura puede pertenecer a varias carreras.
La implementación
sería:
CREATE TYPE carrera AS
(
codigo
CHAR(12),
nombre
CHAR(40),
Asignaturas REF(asignatura) ARR [100]
)INSTANTIABLE NOT FINAL
CREATE TYPE asignatura AS
(
codigo
CHAR(12),
nombre
CHAR(40),
creditos
NUMBER
)INSTANTIABLE NOT FINAL
Si la agregación es uno a uno no necesitaremos un arreglo, bastará con una
referencia a la parte.
75
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Como en la composición las partes pertenecen a un único agregado y se
destruyen junto con él, la mejor estrategia es implementarlo utilizando los
tipos directamente. Por ejemplo, consideremos la relación entre un círculo y
un punto, donde un círculo posee un único punto que es su centro.
La
implementación sería:
CREATE TYPE circulo AS
(
centro
punto,
radio
NUMBER
)INSTANTIABLE NOT FINAL
Si la multiplicidad de la composición es uno a muchos, la implementación es
por medio de un arreglo. Por ejemplo, consideremos la relación entre un
polígono irregular y los puntos (vértices) que lo componen. Esto sería:
CREATE TYPE circulo AS
(
vertices
punto ARR [100]
)INSTANTIABLE NOT FINAL
4.2.6.3 Herencia y Polimorfismo
SQL:1999 permite la herencia simple de tipos, es decir, un tipo puede poseer
un único supertipo.
La sintaxis es bastante sencilla (ver A.2.1), para
entenderla mejor, veamos el siguiente ejemplo.
Consideremos un tipo
llamado figura_geométrica, con la siguiente definición:
CREATE TYPE figura_geometricas AS
(
color_linea
CHAR(10),
Color_fondo
CHAR(10)
)NOT FINAL
METHOD area() RETURNS REAL
METHOD perimetro() RETURNS REAL
A partir de este tipo, podemos definir dos subtipo: triángulo y cuadrado, de
la siguiente manera:
CREATE TYPE punto AS
(
X
REAL,
Y
REAL
)INSTANTIABLE NOT FINAL
REF IS SYSTEM GENERATED
INSTANCE METHOD distanciaA(IN p Punto) RETURNS FLOAT
CREATE TYPE triangulo UNDER figura_geometrica AS
(
a punto,
76
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
b punto,
c punto
) INSTANTIABLE NOT FINAL
OVERRIDING METHOD area() RETURNS REAL
OVERRIDING METHOD perimetro() RETURNS REAL
CREATE TYPE cuadrado UNDER figura_geometrica AS
(
a punto,
b punto,
c punto,
d punto
) INSTANTIABLE NOT FINAL
OVERRIDING METHOD area() RETURNS REAL
OVERRIDING METHOD perimetro() RETURNS REAL
Para indicar el nombre del supertipo, especificamos la cláusula UNDER,
seguido del nombre del supertipo correspondiente. Un tipo, no puede ser
supertipo de si mismo.
Tampoco podemos definir como supertipo a un
subtipo del mismo, sea directo o no.
Una característica esencial de la herencia es que los atributos y métodos del
supertipo pasan a formar parte del subtipo.
Por lo anterior, no podemos
definir el nombre de un atributo igual a otro que se haya heredado. Con
respecto a los métodos, estos pueden ser redefinidos en el subtipo. Esto es
lo que indica la cláusula OVERRIDING que precede a la definición de los
métodos en los tipos triangulo y cuadrado. Al momento de crear el método,
será necesario indicar que el método está siendo sobrescrito. Por ejemplo,
una implementación del método area() del tipo cuadrado sería;
CREATE OVERRIDING METHOD area() RETURNS REAL FOR cuadrado
BEGIN
RETURN a.distanciaA(b) * b.distanciaA(c);
END;
La redefinición y la sobrecarga de métodos son la base del polimorfismo
soportado por el estándar.
Otra característica de la herencia es que toda instancia de un subtipo, es una
instancia de su supertipo directo y también de los indirectos. Así tenemos
que una instancia t del tipo triangulo también es una instancia del tipo
figura_geométrica. Esto significa que la instancia t puede ser utilizada en
cualquier lugar donde se espere una instancia del tipo figura_geométrica.
77
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Por ejemplo, si tenemos una tabla que posea una columna del tipo
figura_geométrica:
CREATE TABLE figuras
(
id NUMBER PRIMARY KEY,
fig figura_geometrica
)
Podemos insertar una fila donde la columna fig almacene un cuadrado, y
otra, donde almacene un triangulo, de la siguiente manera:
INSERT INTO figuras VALUES(1,cuadrado())
INSERT INTO figuras VALUES(1,triangulo())
Si hacemos una consulta sobre la tabla figuras y ejecutamos el método
area() de la columna fig, el sistema determinará el método correspondiente
según el tipo concreto en tiempo de ejecución.
SELECT id, fig.area()
FROM figuras
Además de las columnas, existen otros casos donde podemos sustituir el
valor de una instancia del supertipo, por un valor de su subtipo. Por ejemplo,
en los parámetros de una función, método o procedimiento.
Una excepción a esta característica son las instancias almacenadas como fila
en una typed table. Es decir, si tenemos una typed table tbl_fig cuyo tipo
base sea figura_geometrica, no podremos insertar en ella instancias que no
sean del tipo figura_geometrica.
Sin embargo, podemos lograr la misma
funcionalidad al definir jerarquías de tablas (ver 4.2.5 ).
Al modificar un supertipo con la cláusula ALTER TYPE, estos cambios
afectarán a sus subtipos. Por ejemplo, si agregamos un atributo a la clase
figuras_geometricas, automáticamente, se agrega el atributo a los subtipos,
triangulo y cuadrado. Lo mismo pasa con los métodos.
4.2.7 Concurrencia
Como las versiones anteriores, SQL:1999 soporta la concurrencia de usuarios.
Desde el punto de vista de la orientación a objetos, podríamos decir que
78
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
varios usuarios pueden manipular un mismo objeto a la vez o que varios
objetos pueden ser manipulados por varios usuarios simultanéamele.
Otro aspecto de la concurrencia es que los métodos puedan ser concurrentes,
ya sea multihilo o multiproceso. Si desarrollamos los métodos con SQL/PSM,
no podremos contar con esta característica. Pero si lo implementamos como
una
rutina
externa,
podremos
utilizar
algún
lenguaje
que
soporte
concurrencia, como Java o C.
4.2.8 Manejo de Versiones de objetos y configuraciones
No soportado en el estándar, pero existe una especificación llamada
SQL/Temporal prevista para el 2003 aproximadamente, que se encargará del
manejo de bases de datos históricas, en ella debería estar soportada estas
característica.
4.2.9 Evolución de esquemas y de Instancias
La evolución de esquemas se refiere a la capacidad de modificar la estructura
de los tipos, agregando, modificando o eliminando métodos o atributos y que
estos cambios sean reflejados en todas las estructuras que dependan de él.
La evolución de instancia apunta a dos cosas, la primera es que al alterar un
tipo, dicho cambio debe verse reflejado en las instancias y la otra es contar
con la posibilidad de migrar instancias entre tipos.
La evolución de esquemas está completamente soportada mediante la
sentencia ALTER TYPE.
La evolución de instancias no es soportada completamente, debido a las
restricciones impuestas al predicado ALTER TYPE con respecto a los
atributos. Pero utilizando tablas temporales, lo podemos simular
La migración de clases no es soportada directamente, pero podemos sacar
una copia idéntica de él e insertarla en otra tabla, y eliminar el original. Esto
es posible, gracias a la posibilidad de sobrescribir el OID.
79
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.2.10 Transacciones y recuperación ante fallos
El estándar implementa un robusto sistema de transacciones, incorporando
en esta versión la noción de SAVEPOINT.
Con respecto a la recuperación ante fallos, es una materia dependiente de las
implementaciones del estándar.
4.2.11 Mecanismos de Autorización
Los mecanismos de autorización están basados en las tablas y en los tipos.
Se autoriza o restringe el acceso y manipulación de las tablas o tipos, como
un todo, pero no se puede restringir el acceso sobre un objeto o una fila.
4.2.12 Compatibilidad con el modelo relacional
El estándar ofrece una alta compatibilidad con el modelo relacional, no sólo
por soportarlo directamente, sino por permitir el mezclado de tablas
relacionales y tablas que almacenan objetos. Además podemos definir vistas
de objetos sobre tablas relacionales, permitiendo definir una “capa” de
orientación a objeto sobre nuestros datos relacionales. Las vistas de objeto
también pueden ser creadas jerárquicamente. Por ejemplo, consideremos la
tabla persona:
CREATE TABLE persona
(
rut
CHAR(12) PRIMARY KEY,
nombre
CHAR(40),
fecha_nacim DATE
)
Para definir una vista de objetos sobre esta tabla tendremos que definir un
tipo que represente a una fila de la tabla persona. Por ejemplo
CREATE TYPE tipo_persona AS
(
rut
CHAR(12),
nombre
CHAR(40),
fecha_nacim DATE
)INSTANTIABLE NOT FINAL
INSTANCE METHOD edad() RETURNS REAL
80
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
Ahora, podemos crear una vista de objetos llamada persona_view de la
siguiente manera:
CREATE WIEW persona_view OF tipo_persona
REF IS oid SYSTEM GENERATED
AS (SELECT * FROM persona)
Esto facilita enormemente la migración de bases de datos relacionales a
bases de datos orientadas a objeto, puesto que las aplicaciones actuales
pueden continuar utilizando la tabla relacional, mientras que las nuevas
aplicaciones orientadas a objeto podrán utilizar la vista de objeto, sin que se
produzcan inconsistencias.
81
La Orientación a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.2.13 Limitaciones encontradas en SQL:1999
Al leer este capítulo podrá percatarse que el estándar tiene las siguientes
limitaciones:
•
No podemos sobrecargar las funciones observadoras y mutadoras
•
No podemos especificar un nivel de encapsulamiento (public, private,
protected) sobre los atributos y métodos.
•
No podemos definir constructores
•
No podemos definir atributos estáticos
•
Sólo contamos con los arreglos para definir colecciones.
•
No podemos definir arreglos de múltiples dimensiones (por ejemplo
matrices).
•
Los tipos de referencia sólo pueden almacenar direcciones de objetos
persistentes.
•
No podemos crear módulos o paquetes de objetos.
•
No contamos con herencia múltiple.
•
No está soportado el manejo de versiones y configuraciones de
objetos.
•
No podemos modificar la definición de un atributo ni la interfaz de los
métodos.
82
4.3 Evaluación
En este capítulo evaluaremos la implementación que hace el estándar
SQL:1999 del paradigma de la orientación a objeto.
El objetivo de esta
evaluación es determinar en qué porcentaje son soportadas las características
de la orientación a objeto (ver 2) y los requerimientos para las bases de datos
orientadas a objeto (ver 3.1.2.1), por parte del estandar SQL:1999.
4.3.1 Criterios de evaluación
Para evaluar objetivamente el paradigma de la orientación a objeto en SQL1999, definimos un conjunto de criterios basados en las características del
paradigma de la Orientación a Objeto (ver 2) y en los requerimientos para las
bases de datos orientadas a objeto (ver 3.1.2.1).
Los criterios de evaluación son:
1. Definición de tipos o clases
a. Definición de atributos estáticos
b. Definición de atributos de instancia
c. Constructores definidos por el usuario
d. Métodos estáticos
e. Métodos de instancia
f.
Sobrecarga de métodos
g. Definición de colecciones
h. Clases abstractas
2. Encapsulamiento
a. Atributos y métodos en una sola entidad
b. Distinguir entre interfaz e implementación
c. Visibilidad de métodos (Ej.: Public, private, protected)
d. Visibilidad de atributos (Ej.: Public, private, protected)
3. Modularidad
4. Jerarquía de clases o tipos
a. Asociación
b. Agregación y Composición
83
Orientadas a Objeto en SQL:1999 – Soporte a la Orientación a objeto
c. Herencia Simple
d. Herencia Múltiple
e. Polimorfismo
5. Concurrencia
a. Métodos con múltiples hilos de control
b. Concurrencia de usuarios.
6. Persistencia de objetos
a. Creación
b. Modificación
c. Eliminación
d. Consulta
e. Identificadores de objetos
7. Versiones y configuraciones de objetos
8. Evolución de instancias
9. Evolución de esquemas
a. Agregar Atributos
b. Agregar Métodos
c. Agregar Restricciones sobre objetos persistentes
d. Eliminar Atributos
e. Eliminar Métodos
f.
Eliminar Restricciones
g. Modificar definición de atributos
h. Modificar Interfaz de métodos
i.
Modificar Implementación de métodos
j.
Modificar Restricciones
k. Deshabilitar y habilitar restricciones
10. Transacciones y recuperación ante fallos
11. Mecanismos de autorización basados en objetos
12. Compatibilidad con el modelo relacional.
Cada criterio lo evaluaremos con los siguientes valores:
Si la característica:
Está presente
No está presente, pero se puede simular
No está presente
Valoración
100%
60%
0%
84
Orientadas a Objeto en SQL:1999 – Soporte a la Orientación a objeto
4.3.2 Matriz de evaluación
a. Definición de atributos estáticos
Valoración
1. Definición de tipos o clases
Final
Parcial
Características
95,00%
60%
b. Definición de atributos de instancia
100%
c. Constructores definidos por el usuario
100%
d. Métodos estáticos
100%
e. Métodos de instancia
100%
f. Sobrecarga de métodos
100%
g. Definición de colecciones
100%
h. Clases abstractas
100%
2. Encapsulamiento
80,00%
a. Atributos y métodos en una sola entidad
100%
b. Distinguir entre interfaz e
100%
implementación
c. Visibilidad de métodos (Ej.:Public,
60%
private, protected)
d. Visibilidad de atributos (Ej.: Public,
60%
private, protected)
3. Modularidad
60,00%
4. Jerarquía de clases o tipos
92,00%
a. Asociación
100%
b. Agregación y Composición
100%
c. Herencia Simple
100%
d. Herencia Múltiple
e. Polimorfismo
60%
100%
5. Concurrencia
100,00%
a. Métodos con múltiples hilos de control
100%
b. Concurrencia de usuarios.
100%
85
Orientadas a Objeto en SQL:1999 – Soporte a la Orientación a objeto
6. Objetos Persistentes
100,00%
a. Creación
100%
b. Modificación
100%
c. Eliminación
100%
d. Consulta
100%
e. Identificadores de objetos
100%
7. Versiones y configuraciones de objetos
0,00%
8. Evolución de instancias
60,00%
9. Evolución de esquemas
92,00%
a. Agregar Atributos
100%
b. Agregar Métodos
100%
c. Agregar
Restricciones
sobre
objetos
100%
persistentes
d. Eliminar Atributos
100%
e. Eliminar Métodos
100%
f. Eliminar Restricciones
100%
g. Modificar definición de atributos
60%
h. Modificar Interfaz de métodos
60%
i. Modificar Implementación de métodos
100%
j. Modificar Restricciones
100%
10. Transacciones y recuperación ante fallos
11. Mecanismos de autorización basados en
100%
60%
objetos
12. Compatibilidad con el modelo relacional.
Promedio
100%
78,25%
86
5 Oracle 8i y la Orientación a
Objeto.
5.1 Introducción
Oracle fue el primer servidor de bases de datos relacional, y desde entonces
ha sido uno de los líderes de la industria, realizando grandes inversiones en
investigación
y
desarrollo,
además,
participa
activamente
en
la
estandarización del lenguaje SQL. Entre las características más importantes
de SABD Oracle 8i destacan [31]:
•
Entorno cliente / servidor y procesamiento distribuido.
•
Bases de datos de gran tamaño (Terabyte de datos).
•
Gran número de usuarios concurrente.
•
Conectividad con distintos sistemas operativos y distintas máquinas.
•
Alto desempeño en procesamiento de transacciones.
•
Alta disponibilidad, puede trabajar 24 horas por día sin una baja de
desempeño y algunas operaciones como respaldos se pueden hacer
sin “bajar” el servidor.
•
Disponibilidad controlada.
•
Se ajusta a los estándares de la industria.
•
Integridad de la base de datos reforzada.
•
Portabilidad y compatibilidad.
•
Capacidad de replica de bases de datos.
A partir de la versión 8 de Oracle, comenzaron a incorporar características
orientadas a objeto, como definición de tipos, creación de tablas y vistas de
objeto, etc.
En este
capítulo se revisarán y analizarán los aspectos más
importantes de Oracle 8i relacionados con la tecnología de objetos
incorporada,
para finalmente realizar una evaluación objetiva de esta
tecnología.
Como observación, asumiremos que el lector está familiarizado con SQL 92,
especialmente en lo relacionado con la definición, manipulación y consulta
de tablas relacionales y, por lo menos, posee una noción sobre los
procedimientos almacenados.
88
5.2 Soporte a la Orientación a Objeto
Para analizar el soporte de la orientación a objeto en ORACLE, como lo
hicimos con SQL:1999, nos basaremos en los conceptos básicos de la
orientación a objeto (ver 2) y en los requerimientos para las bases de datos
orientadas a objeto (ver 3.1.2.1 ). En lo posible, mantendremos la misma
estructura de presentación utilizada al analizar SQL:1999 para facilitar su
comparación con Oracle.
5.2.1 Tipos, abstracción y clases
Como explicamos en la sección 2.2.6
los conceptos de clase y tipo son
distintos, pero muchos lenguajes no hacen dicha distinción e incorporan
ambos conceptos bajo un mismo nombre ya sea el de clase o de tipo. En
Oracle el nombre empleado es tipo objeto (object type), que es un tipo de
datos definido por el usuario, que luego de ser descrito, pasa a formar parte
del sistema de tipos del lenguaje, quedando disponible para todos los
usuarios que tengan los privilegios de acceso correspondientes.
Un tipo objeto implementa una abstracción y por ende está compuesto por
[31]:
1. nombre, que lo identifica dentro de la base de datos y debe ser único
dentro del esquema en que se está definiendo
2. Atributos, cada uno con un nombre y un tipo de datos, que puede ser
un tipo primitivo u otro tipo definido por el usuario
3. métodos. Son funciones o procedimientos escritos en PL/SQL, Java o
C. Los métodos escritos en PL/SQL o en Java son almacenados en la
base de datos (de la misma manera que un procedimiento
almacenado)
y
los
métodos
escritos
en
C
son
invocados
externamente.
Describiremos los atributos y métodos con detenimiento más adelante en
las secciones 5.2.1.3 y 5.2.1.4 respectivamente.
89
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
5.2.1.1 Estructura de un tipo objeto
Un tipo objeto tiene dos partes: una especificación y un cuerpo.
La
especificación es la interfaz pública del tipo y en ella se declaran sus
atributos y la especificación de sus métodos (sin su implementación). En el
cuerpo se especifican e implementan los métodos que aparecieron en la
especificación del tipo[32]. El cuerpo es la parte privada del tipo.
especificación
Interfaz Pública
Declaración de Atributos
Especificación de Métodos
Cuerpo
1
Implementación
Privada
Cuerpo de los Métodos
figura 5: Estructura de un tipo objeto.
Esta separación permite modificar los algoritmos que implementan los
métodos, sin que esto afecte a los usuarios del tipo (aplicaciones), siempre y
cuando no alteremos su interfaz. De este modo, el cuerpo pasa a ser una
“caja negra”, donde las aplicaciones clientes sólo conocen la interfaz del
método.
Como muestra la figura 5, sólo podemos declarar atributos en la
especificación del tipo, y éstos se declaran antes que los métodos. No es
necesario definir el cuerpo de un tipo cuando este no especifica métodos[32].
5.2.1.2 Sintaxis para la creación de tipos
Para definir la interfaz del tipo se utiliza la sentencia SQL CREATE TYPE Y
para el cuerpo CREATE TYPE BODY
[41]. No se pueden definir tipos o
cuerpos de tipos en bloques PL/SQL, subprogramas o paquetes.
Para describir la sintaxis usaremos la siguiente notación:
90
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
•
Las palabras en mayúsculas son palabras reservadas
•
Los paréntesis cuadrados, [ ], indican que su contenido es opcional.
•
El paréntesis de llave, { }, agrupan elementos.
•
La barra vertical, |, indica que los elementos son alternativos (Es
como un OR exclusivo o XOR).
•
Los puntos suspensivos, ..., indican repetición.
5.2.1.2.1 CREATE TYPE
La sintaxis para el predicado CREATE TYPE es la siguiente [41][32]:
CREATE [OR REPLACE] TYPE [schema.]type_name
[AUTHID {CURRENT_USER | DEFINER}] {IS | AS} OBJECT (
attribute_name datatype [, attribute_name datatype]...
[{MAP | ORDER} MEMBER function_spec,]
[{MEMBER | STATIC} subprogram_spec [call_spec]
[, {MEMBER | STATIC} subprogram_spec [call_spec]]...]
);
Descripción de la sintaxis.
OR REPLACE.
Cláusula opcional que permite remplazar la definición
anterior del tipo (si existe) con la nueva. No se puede reemplazar un tipo
si existen tablas, vistas u otros tipos que dependan de él [41].
[schema.]type_name. Es el nombre del tipo, el cual puede ir precedido
con el nombre del esquema en el que se quiere crear, separados por un
punto. Si no se especifica el esquema, el tipo se crea en el esquema del
usuario actual[41]. Estos son ejemplos de nombres válidos:
Persona, esquema.persona, miguel.persona_tipo, etc.
AUTHID CURRENT_USER o AUTHID DEFINER. Especifica si los métodos
se ejecutan con los privilegios y en el esquema del usuario actual(AUTHID
CURRENT_USER) o con los privilegios y en el esquema de usuario que
definió el tipo (AUTHID DEFINER).
Esta cláusula también se aplica al
cuerpo del tipo [41]. La cláusula por defecto es AUTHID CURRENT_USER
[31].
91
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
attribute_name. Nombre del atributo que debe ser único dentro del tipo,
pero puede repetirse en otros [31].
datatype.
Tipo de dato del atributo que puede ser un tipo de dato
definido por el usuario o bien un tipo de dato primitivo con la excepción
de: ROWID, UROWID, LONG, LONG ROW, NCLOB, NCHAR y NBARCHAR2
[41].
MEMBER. Especifica que el método que se está declarando es del tipo
miembro (ver sección 5.2.1.4.2 ), esto significa que su invocación será a
partir de un objeto. Por ejemplo, si tenemos un tipo persona con un
método miembro edad y un objeto p, para saber la edad de p se escribe:
p.edad().
STATIC.
Especifica que el método que se está declarando es del tipo
Estático (ver sección 5.2.1.4.3 ). Un método estático, a diferencia de un
método miembro, se invocan a partir del nombre del tipo, y no de un
objeto. Tomando el ejemplo anterior, si el método edad fuera estático se
invocaría: persona.edad().
Al no haber objeto de la invocación no
podemos acceder a los atributos de este.
[{MAP | ORDER} MEMBER function_spec,].
Especifica una función
miembro que el sistema emplea para realizar comparaciones de objetos de
este tipo.
La función de comparación puede ser de dos tipos MAP u
ORDER y un tipo puede tener sólo una de ellas[31]. Para mayor
información vea la sección 5.2.1.4.4
subprogram_spec.
Es la especificación de un procedimiento o de una
función que consta de un nombre y de una lista opcional de parámetros.
Además de lo anterior, las funciones cuentan con un valor de retorno. El
formato para describir funciones es:
FUNCTION name [(parameter [IN|OUT|IN OUT] datatype
[, parameter [IN|OUT|IN OUT] datatype]…)] RETURN datatype
y para procedimientos corresponde a:
PROCEDURE name [(parameter [IN|OUT|IN OUT] datatype
[, parameter [IN|OUT|IN OUT] datatype]…)]
92
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Donde
name es el nombre de la función o procedimiento,
parameter es el nombre del parámetro.
IN indica que se debe especificar un valor para el argumento al
invocar el método.
OUT indica que el argumento es usado por el subprograma para
devolver un valor al punto de llamada (o invocación del método),
una vez terminada la ejecución.
IN OUT indica que el argumento es utilizado como IN y OUT a la
vez.
datatype es el tipo de dato del parámetro
RETURN datatype es el tipo de dato de retorno de la función.
Al no especificar las cláusulas IN, OUT o IN OUT, el valor por defecto es IN.
call_spec.
Esta cláusula indica que el método está implementado en java
o en C. Call_spec, especifica cómo llamar al método java o función C, y
cómo trasladar los parámetros y los valores de retorno. Si para todos los
métodos se especifica un call_spec, entonces no es necesario definir un
cuerpo del tipo con CREATE TYPE BODY.
El formato para el call_spec en el caso que el lenguaje sea java es:
LANGUAJE JAVA NAME
’ string ’
En el caso que el lenguaje sea C:
LANGUAJE C [NAME name] LIBRARY lib_name [WITH CONTEXT]
[PARAMETERS ( parameters )]
Para más información sobre métodos implementados con java o C, vea las
secciones 5.2.1.5.2 ó 5.2.1.5.3 respectivamente.
93
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
5.2.1.2.2 CREATE TYPE BODY
La sintaxis para el predicado CREATE TYPE BODY es la siguiente:
CREATE [OR REPLACE] TYPE BODY [schema.]type_name { IS | AS}
{{MAP|ORDER}MEMBER function_spec {IS|AS} {pl/sql_block|call_spec};
|{MEMBER|STATIC}subprogram_spec{IS|AS}{pl/sql_block|call_spec};}
[{MEMBER|STATIC}subprogram_spec{IS|AS}{pl/sql_block|call_spec};]...
END;
Descripción de la sintaxis.
OR REPLACE. Funciona de la misma manera que en CREATE TYPE [41].
[schema.]type_name. El nombre del cuerpo debe coincidir con el nombre
del tipo para el cual se define el cuerpo.
MEMBER, STATIC, MAP, ORDER, function_spec, subprogram_spec.
Tienen el mismo significado que en CREATE TYPE, además, estas
especificaciones deben coincidir exactamente con las definidas en el
predicado CREATE TYPE correspondiente.
{ pl/sql_block | call_spec }. Indican la manera en que se implementan los
métodos.
La cláusula pl/sql_block representa un bloque PL/SQL que
contiene un conjunto de instrucciones que implementa el método en dicho
lenguaje. Para el caso de call_spec, si éste aparece en CREATE TYPE, éste
debe estar presente en CREATE TYPE BODY.
Si no aparece quedamos
libres de escoger el lenguaje de implementación de los métodos, y
cambiarlo cuando queramos.
Para una mejor comprensión de cómo se crea un tipo objeto, veamos el
siguiente ejemplo tomado de [32], que corresponde a la implementación de
un tipo para la manipulación de números complejos. Un numero complejo
consta de dos partes, una real y otra imaginaria, ambas dentro del rango de
los números reales. Además existen una serie de operaciones matemáticas
que se pueden aplicar a dichos números. Las implementadas para este tipo
son las cuatro operaciones básicas (suma, resta, multiplicación y división). El
texto precedido con “- -“ es un comentario.
94
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
CREATE TYPE Complex AS OBJECT (
-- atributos
rpart REAL,
ipart REAL,
-- métodos
MEMBER FUNCTION suma (x Complex) RETURN Complex,
MEMBER FUNCTION resta (x Complex) RETURN Complex,
MEMBER FUNCTION mult (x Complex) RETURN Complex,
MEMBER FUNCTION div (x Complex) RETURN Complex
);
CREATE TYPE BODY Complex AS
MEMBER FUNCTION suma (x Complex) RETURN Complex IS
BEGIN
RETURN Complex(rpart + x.rpart, ipart + x.ipart);
END suma;
MEMBER FUNCTION resta (x Complex) RETURN Complex IS
BEGIN
RETURN Complex(rpart - x.rpart, ipart - x.ipart);
END resta;
MEMBER FUNCTION mult (x Complex) RETURN Complex IS
BEGIN
RETURN Complex(rpart * x.rpart - ipart * x.ipart ,
rpart * x.ipart + ipart * x.rpart );
END mult;
MEMBER FUNCTION div (x Complex) RETURN Complex IS
z REAL := x.rpart**2 + x.ipart**2;
BEGIN
RETURN Complex((rpart*x.rpart + ipart*x.ipart)/z,
(ipart*x.rpart - rpart*x.ipart)/z);
END div;
END;
Como sugerencia, comparar esta implementación con la mostrada en la
sección 4.2.1.3.4 SQL:1999.
5.2.1.3 Atributos
Todo tipo objeto debe poseer a lo menos un atributo, y como máximo 1.000.
Un atributo consta de un nombre y un tipo de dato, donde el nombre debe
ser único dentro del tipo objeto, y el tipo de datos del atributo puede ser otro
tipo definido por el usuario o un tipo primitivo, con las excepciones ROWID,
UROWID, LONG, LONG ROW, NCLOB, NCHAR y NBARCHAR2.
Entre los tipos de datos primitivos existe uno denominado REF, que permite
almacenar una referencia a un tipo objeto. Gracias a él podemos definir un
tipo objeto recursivo que es aquel donde uno o más de sus atributos tienen
95
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
como tipo de dato una referencia a si mismo. Por ejemplo, consideremos una
lista enlazada con dos atributos, uno llamado info para almacenar un número
y un atributo next que es una referencia a la lista siguiente. Para construirlo
podemos escribir:
CREATE OR REPLACE TYPE lista AS OBJECT
(
info number,
next REF lista
);
Una referencia (REF), almacena un puntero lógico a un objeto, lo que nos
permite acceder a él directamente. El manejo de las referencias en Oracle, es
semejante al de JAVA. Por ejemplo, para obtener el atributo info de la lista
siguiente (referenciada por next) a la lista L, seria:
... L.next.info ...
Como en muchos lenguajes de programación (Ej.: c, pascal, etc) un tipo no
puede tener un atributo del mismo tipo que él.
Por ejemplo si intenta crear
el tipo lista mostrado anteriormente, pero omitiendo la palabra REF obtendrá
un error de compilación. Las siguientes líneas muestran la ejecución de este
ejemplo en SQL*PLUS:
SQL> create type lista as object (
2
info number,
3
next lista --esta linea es ilegal.
4 )
5 /
Warning: Type created with compilation errors.
SQL> show errors;
Errors for TYPE LISTA:
LINE/COL
-------0/0
3/7
ERROR
-----------------------------------------------------PL/SQL: Compilation unit analysis terminated
PLS-00318: type "LISTA" is malformed because it is a
non-REF mutually recursive type
Si está interesado en crear tipos recursivos, le recomendamos la referencia
bibliográfica [2],
ahí explican cómo crear estructuras de red, árbol, listas
enlazadas y de anillo en Oracle 8.
Al observar los ejemplos se percatará que si comparamos la definición de
atributos con la definición de columnas de una tabla, son muy similares, pero
96
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
existen diferencias notables. Para apreciar las diferencias y semejanzas
veremos la siguiente definición de un tipo empleado y de una tabla empleado
Creación del tipo empleado
CREATE OR REPLACE TYPE
(
rut
nombre
fecha_ingreso
salario
);
empleado AS OBJECT
VARCHAR2(10),
VARCHAR2(30),
DATE,
NUMBER
Creación de la tabla empleado
CREATE TABLE empleado
(
rut
VARCHAR2(10) CONSTRAINT pk_emp PRIMARY KEY,
nombre
VARCHAR2(30) CONSTRAINT nn_ename NOT NULL,
fecha_ingreso DATE DEFAULT SYSDATE,
sueldo
NUMBER CONSTRAINT ck_suel CHECK(sueldo>95000)
);
En ambas definiciones (atributos y columnas) especificamos un nombre y un
tipo de datos, pero cuando definimos un tipo objeto, no podemos indicar
valores iniciales ni imponer restricciones como NOT NULL a un atributo [32].
Estas restricciones podrán ser impuestas cuando definamos una tabla que
almacene objetos.
Otra restricción que tenemos a la hora de definir un tipo objeto, es que el
tipo de datos de un atributo debe existir. En el siguiente ejemplo la primera
sentencia CREATE TYPE es ilegal, porque el tipo Departamento todavía no
existe:
CREATE OR REPLACE TYPE Empleado AS OBJECT
(
rut
varchar2(9),
nombre varchar2(20),
dept
REF Departamento – - esta linea es ilegal
);
CREATE OR REPLACE TYPE Departamento AS OBJECT
(
nombre varchar2(20),
jefe
Empleado
);
Una solución podría ser definir primero el tipo Departamento, pero esto
provocaría el mismo error al tratar de definir el atributo jefe de un tipo que
97
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
todavía no existe.
Este problema se produce porque los dos tipos son
mutuamente dependientes, es decir, uno depende del otro a través de una
referencia [32]. Para solucionar este problema existe una sentencia CREATE
TYPE especial, denominada forward type definition (definición de tipo
adelantada) cuya sintaxis es la siguiente:
CREATE [OR REPLACE] TYPE [schema.]type_name;
El tipo objeto creado con esta sentencia es denominado tipo objeto
incompleto, por no contar con atributos o métodos, los que serán definidos
más adelante con la sentencia CREATE TYPE normal, dejando de ser
incompleto.
Siguiendo con el ejemplo anterior, ahora podemos solucionar el problema de
la dependencia mutua al definir por adelantado el tipo Departamento:
-- definición adelantada del tipo departamento
CREATE OR REPLACE TYPE Departamento ;
CREATE OR REPLACE TYPE Empleado AS OBJECT
(
rut
varchar2(9),
nombre varchar2(20),
dept
REF Departamento -- No produce error.
);
–- definición normal del tipo departamento
CREATE OR REPLACE TYPE Departamento AS OBJECT
(
nombre varchar2(20),
jefe
Empleado
);
Es necesario señalar que no es posible definir un atributo a partir de un tipo
incompleto, sólo se pueden definir referencias a tipos incompletos.
Por
ejemplo, si creamos un tipo departamento y luego tratamos de definir un
atributo de este tipo, obtendremos un error de compilación. Las siguientes
líneas fueron ejecutadas en SQL*PLUS, y ejemplifican lo antes descrito.
SQL> create type departamento;
2 /
Type created.
SQL> create type Empleado as Object
2 (
3
rut varchar2(9),
4
dep departamento –-esta linea es ilegal.
5 );
98
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
6
/
Warning: Type created with compilation errors.
SQL> show errors;
Errors for TYPE EMPLEADO:
LINE/COL
-------0/0
4/8
ERROR
----------------------------------------------------PL/SQL: Compilation unit analysis terminated
PLS-00311: the declaration of "DEPARTAMENTO" is
incomplete or malformed
Como consecuencia de lo anterior, no podemos tener dos tipos mutuamente
dependientes si el atributo dependiente de uno de ellos (o de ambos) no es
una referencia al otro tipo.
5.2.1.4 Métodos
Los métodos no son más que funciones o procedimientos almacenados que
se
asocian
a
un
tipo
específico,
y
no
pueden
ser
invocados
independientemente.
Existen cuatro categorías para los métodos estas son: Constructor,
miembro, estático y comparación.
5.2.1.4.1 Constructor
Todos los tipos objeto definidos por el usuario poseen un método
constructor generado por el sistema, que es una función con el mismo
nombre que el tipo. Los parámetros formales de esta función coinciden
exactamente con los atributos del tipo, es decir, son declarados en el
mismo orden, con el mismo nombre y del mismo tipo de dato que los
atributos [32]. El valor de retorno del constructor es un nuevo objeto del
mismo tipo al que pertenece el constructor, donde los valores de los
atributos fueron inicializados con los valores pasados por parámetro al
momento de llamar al constructor [31].
Por ejemplo, consideremos el
siguiente tipo:
CREATE OR REPLACE TYPE Persona AS OBJECT
(
rut
VARCHAR2(10),
nombre
VARCHAR2(30),
99
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
);
Si queremos crear un objeto Persona donde el rut sea 13.131.344-6 y el
Nombre Miguel Romero, utilizaremos el método constructor de la
siguiente manera
... Persona(‘13131344-6’,’Miguel Romero’)
Como el método constructor es una función, sólo puede ser utilizar dentro
de una expresión en la que se espera un objeto de ese tipo.
Los
constructores también pueden ser utilizados en sentencias SQL.
Muchos lenguajes como JAVA, permiten la sobrecarga de constructores,
esto no es posible en Oracle 8i, y tampoco podemos redefinirlo.
5.2.1.4.2 Miembro (member)
Para especificar un método miembro se antepone la palabra reservada
MEMBER, y como mencionamos anteriormente, estos son invocados a
partir de un objeto. Los métodos miembro son definidos por el usuario al
momento de especificar el tipo, pudiendo ser una función o un
procedimiento.
Por ejemplo, podemos definir un tipo punto para
representar las coordenadas (X,Y) con los
método moverA (cambia la
ubicación del punto) y distanciaA (calcula la distancia a otro punto). El
código para la creación del tipo es el siguiente:
CREATE OR REPLACE TYPE Punto AS OBJECT
(
X
number,
Y
number,
MEMBER PROCEDURE moverA(X IN number, Y IN number),
MEMBER FUNCTION distanciaA(p IN Punto) RETURN NUMBER
);
Hasta este momento, sólo hemos descrito la interfaz del método, falta su
implementación. Las siguientes líneas implementan los métodos:
CREATE OR REPLACE TYPE BODY Punto AS
MEMBER PROCEDURE moverA(X IN number, Y IN number) IS
BEGIN
SELF.X:=X;
SELF.Y:=Y;
END moverA;
MEMBER FUNCTION
distanciaA(p IN Punto) RETURN NUMBER IS
100
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
-- Funcion POWER(m,n) retorna m elevado a n.
-- Funcion SQRT(m) retorna la raiz cuadrada de m.
-- Este metodo entrega la distancia euclidiana entre el
-- objeto de la invocación y el punto p.
BEGIN
RETURN SQRT(POWER((x - p.x),2) + POWER((y - p.y),2));
END distanciaA;
END;
El primer parámetro de un método es siempre el objeto de la invocación
llamado SELF cuyo tipo de dato es el mismo al que pertenece el método.
El argumento SELF esta implícito al declarar un método de este tipo (no es
necesario declararlo) [32].
Este parámetro nos permite acceder a los
atributos o métodos del objeto de la invocación.
El uso del parámetro
SELF sólo es obligatorio cuando un método cuenta con un parámetro o
una variable con el mismo nombre que un atributo. Por eso, en el método
moverA se utiliza el parámetro SELF (ej: SELF.X:=X;), y en el método
distanciaA es omitido (ej: POWER((x - p.x),2)).
El modo por defecto para el parámetro SELF es IN para el caso de las
funciones miembro e IN OUT para el caso de los procedimientos miembro
[32]. Esto significa que no podemos actualizar los atributos del objeto en
una función pero si en un procedimiento.
Si queremos un pasaje de
parámetros distinto será necesario declarar explícitamente el parámetro
SELF, teniendo en cuenca lo siguiente:
•
SELF debe ser el primer argumento.
•
No se puede declarar el modo OUT para SELF.
•
SELF no puede ser de un tipo diferente al del tipo en el que se
declara el método.
Por ejemplo:
CREATE TYPE Persona as OBJECT
(
nombre VARCHAR(40),
MEMBER FUNCTION setNombre(SELF IN OUT Persona,
Nom IN VARCHAR) return BOOLEAN
);
Las funciones miembro pueden ser invocadas desde sentencias SQL
(SELECT, INSERT, DELETE, etc) siempre que el modo de todos sus
parámetros sea IN, de lo contrario obtendremos el siguiente error:
101
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
SQL> select p.setNombre('Miguel Romero') from per p;
select p.setNombre('Miguel Romero') from per p
*
ERROR at line 1:
ORA-06572: Function SETNOMBRE has out arguments
Los procedimientos miembro no pueden ser invocados desde sentencias
SQL, sólo a través de objetos transitorios desde el lenguaje de
programación.
5.2.1.4.3 Estático (Static)
Un método estático al igual que un método miembro, puede ser un
procedimiento o una función, pero a diferencia de este, no podemos
declarar el parámetro SELF, implícita o explícitamente. Debido a esto, en
un método estático no podemos acceder a los atributos del tipo, ni
referenciar a SELF [32].
El uso más común de los métodos estáticos es crear funciones que hagan
las veces de constructor, supliendo así la carencia de constructores
definidos por el usuario. Por ejemplo para el tipo Punto descrito en la
sección 5.2.1.4.2 el constructor por defecto construye un punto a partir
de las coordenadas X e Y (ej.: Punto(3,5) ). Si quisiéramos construir un
punto a partir de otro, podríamos hacerlo definiendo un método estático
de la siguiente manera:
CREATE OR REPLACE TYPE Punto AS OBJECT
(
X
number,
Y
number,
MEMBER PROCEDURE moverA(X IN number, Y IN number),
MEMBER FUNCTION distanciaA(p IN Punto) RETURN NUMBER,
STATIC FUNCTION constructor(p IN Punto) RETURN PUNTO
);
y luego lo invocaríamos como :
...Punto.constructor(P)
siendo P un objeto del tipo Punto.
5.2.1.4.4 Comparación (Map u Order)
102
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Los valores de
tipos de datos como REAL o CHAR tienen un orden
predefinido (1,2,3 ó A,B,C... etc.), lo que permite su comparación (=, <, >,
etc.) [32].
Pero las instancias de un tipo objeto no tienen un orden
predefinido.
Para poder realizar comparaciones, existen dos tipos de
métodos que se definen anteponiendo las palabras reservadas MAP u
ORDER.
Un tipo objeto puede tener solamente una función de
comparación ya sea MAP u ORDER.
Un método de comparación del tipo MAP es una función miembro que no
posee argumentos y cuyo valor de retorno es de uno de los siguientes
tipos de datos escalares: DATE, NUMBER, VARCHAR2, o un tipo ANSI SQL
como CHARACTER o REAL [32].
Por ejemplo, consideremos un tipo
Racional para representar los números racionales (ej.: ½).
CREATE TYPE Racional AS OBJECT
(
num
INTEGER,
den
INTEGER,
MAP MEMBER FUNCTION convert RETURN REAL
);
CREATE TYPE BODY Rational AS
MAP MEMBER FUNCTION convert RETURN REAL IS
BEGIN
RETURN num / den ;
END convert;
END;
Un método del tipo MAP deberá entrega la posición relativa que ocuparía
el objeto si se ordenara el universo completo de objetos del mismo tipo.
Para el caso anterior es muy conveniente una función de ordenación del
tipo map, porque todo número racional puede ser convertido a un número
real.
Pero no todos los tipos objetos que definamos tendrán esa
característica. Para todos los tipos objetos que no puedan ser convertidos
a uno de los tipos escalares nombrados anteriormente existe otro tipo de
método de comparación llamado ORDER.
Un Método de tipo ORDER es una función miembro que tiene
obligatoriamente dos parámetros: el parámetro SELF (ver sección 5.2.1.4.2
), y otro objeto del mismo tipo. La función retorna un valor numérico, que
103
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
puede ser negativo, cero o positivo. Esto significa que el parámetro SELF
es menor (negativo), igual (cero) o mayor (positivo) que el otro parámetro.
Por ejemplo:
CREATE TYPE Producto AS OBJECT
(
id
NUMBER,
nombre
VARCHAR2(40),
ORDER MEMBER FUNCTION comparTo(p Producto) RETURN NUMBER
);
CREATE TYPE BODY Producto AS
ORDER MEMBER FUNCTION comparTo(p Producto) RETURN NUMBER
BEGIN
IF id < p.id THEN
RETURN –1;
ELSIF id > p.id THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END comparTo;
END;
Si un método del tipo ORDER es llamado con un valor NULL, retorna un
NULL.
Gracias a los métodos de comparación, tanto MAP u ORDER, el sistema
puede evaluar expresiones booleanas como X > Y o hacer comparaciones
implícitas en las cláusulas GROUP BY, DISTINCT y ORDER BY.
Si no se
especifica una función miembro del tipo MAP u ORDER, Oracle no podrá
hacer comparaciones en bloques PL/SQL, ni en las sentencias SQL,
solamente podrá saber si dos objetos son iguales o no.
Cuando definimos funciones miembro del tipo MAP, el sistema puede
realizar ciertas optimizaciones. Por esta razón siempre que pueda utilice
métodos del tipo MAP.
5.2.1.4.5 Sobrecarga de métodos.
La sobrecarga de métodos como explicamos en la sección 2.2.5.1.1 ,
consiste en tener dos o más métodos con el mismo nombre pero con
distintos parámetros formales, ya sea en número, orden, o tipo de dato.
104
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
La sobrecarga es soportada, únicamente, para los métodos miembro y
estático. No podemos sobrecargar métodos si sus parámetros formales
difieren únicamente en el modo (IN, OUT, IN OUT). Tampoco podemos
sobrecargar funciones miembro, que difieran únicamente en el tipo de
dato del valor de retorno [32].
Siguiendo con el ejemplo del tipo Punto, sobrecargaremos el método
moverA, para que acepte un Punto como argumento.
CREATE OR REPLACE TYPE
(
X
number,
Y
number,
MEMBER PROCEDURE
MEMBER PROCEDURE
MEMBER FUNCTION
);
Punto AS OBJECT
moverA(X IN number, Y IN number),
moverA(P IN Punto),
distanciaA(p IN Punto) RETURN NUMBER
5.2.1.5 Alternativas para la implementación de los métodos
Tenemos tres alternativas para implementar los métodos, PL/SQL, JAVA o C.
Cada lenguaje tiene ventajas y desventajas comparativas, por esta razón, es
importante escoger el que mejor se ajuste a nuestras necesidades, que
podrían ser: facilidad de uso, disponibilidad de personal capacitado,
portabilidad, compatibilidad con sistemas existentes o heredados [30]. Sin
embargo, la elección podría estar estrechamente ligada a la naturaleza de la
aplicación y la forma en que trabajará con Oracle. Bajo este punto de vista,
considere lo siguiente [30]:
•
PL/SQL está especialmente diseñado para el procesamiento de
transacciones SQL.
•
C es el lenguaje indicado para los métodos que realizan cálculos
intensivos, gracias a su alta eficiencia y la posibilidad de programar a
bajo nivel.
•
JAVA es altamente portable y seguro.
Desde el punto de vista del rendimiento, PL/SQL se ejecuta ligeramente mejor
que JAVA interpretado [6], pero en Oracle 9i, es posible compilar JAVA a
código nativo, dicho código, se ejecutará diez veces más rápido que en
PL/SQL.
El Código nativo de JAVA posee un rendimiento similar al de los
105
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
métodos escritos con C. Esto se debe a que Oracle, primero pasa el código
java a C, y luego lo compila.
5.2.1.5.1 Implementación de los métodos con PL/SQL
PL/SQL es el lenguaje por defecto (no se necesita un call_spec) para la
implementación de métodos y es el que hemos utilizado para la
implementación de los ejemplos.
Como debe haber apreciado implementar los métodos en PL/SQL resulta
fácil, gracias a que está transparentemente incorporado en las sentencias
CREATE TYPE y CREATE TYPE BODY.
Otra característica que facilita el
trabajo, es que los tipos definidos en SQL pueden ser utilizados
directamente en PL/SQL sin la necesidad de importarlos o de declararlos.
Además existe una correspondencia exacta de tipos.
Ejemplo:
CREATE or replace TYPE Empleado AS OBJECT (
rut
VARCHAR2(10),
nombre
VARCHAR2(10),
cargo
VARCHAR2(9),
fechaIng
DATE,
sueldo
NUMBER(9),
comision
NUMBER(9),
anticipo
NUMBER(9),
MEMBER FUNCTION sueldo_liquido RETURN NUMBER,
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER)
);
CREATE OR REPLACE TYPE BODY Empleado IS
MEMBER FUNCTION sueldo_liquido RETURN NUMBER IS
BEGIN
RETURN (sueldo + comision)-anticipo;
END sueldo_liquido;
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER) IS
BEGIN
sueldo:=sueldo+aumento;
END aumento_sueldo;
END;
5.2.1.5.2 Implementación de métodos con JAVA
Los
métodos
de
un
tipo
objeto
no
pueden
ser
implementados
directamente con el lenguaje java. Para esto debemos crear una clase (en
java) con sus propios atributos y métodos, cargarla en el servidor, y luego,
asociar los métodos del tipo objeto (en Oracle) con los de la clase java
106
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
correspondiente.
Dicha asociación se logra mediante las cláusulas AS
LANGUAGE JAVA NAME ‘...’, las cuales pueden ser especificadas en la
sentencia CREATE TYPE y/o en CREATE TYPE BODY.
Consideremos el mismo tipo empleado utilizado como ejemplo en la
sección anterior (5.2.1.5.1 , pero asociando sus métodos con los de la
clase EmpleadoBody previamente cargada en el servidor:
CREATE or replace TYPE Empleado AS OBJECT (
rut
VARCHAR2(10),
nombre
VARCHAR2(10),
cargo
VARCHAR2(9),
fechaIng
DATE,
sueldo
NUMBER(9),
comision
NUMBER(9),
anticipo
NUMBER(9),
MEMBER FUNCTION sueldo_liquido RETURN NUMBER
AS LANGUAGE JAVA
NAME 'EmpleadoBody.sueldoLiquido() return
java.math.BigDecimal',
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER)
AS LANGUAGE JAVA
NAME 'EmpleadoBody.aumentoSueldo(java.math.BigDecimal)'
);
Al indicar cómo llamar al método de la clase java correspondiente,
también se especifica el tipo (clase java) de retorno y el de cada uno de los
parámetros. No se puede omitir la jerarquía de paquetes del tipo. Otra
cosa importante es que los tipos deben ser compatibles con su
contraparte de Oracle. Para ver en detalle la compatibilidad de tipos vea la
referencia [43].
Cuando invoquemos un método (que no sea estático) sobre una instancia
del tipo objeto Empleado, ésta invocará al método correspondiente, sobre
una instancia de la clase EmpleadoBody. Para que los métodos se ejecuten
correctamente, la instancia de la clase EmpleadoBody debe tener el mismo
estado que su contraparte y los cambios de estado deben reflejarse en
ambas instancias.
Para lograr esto, la clase EmpleadoBody, deberá
implementar la interfaz SQLData, la que define los métodos readSQL() y
writeSQL() [43]. Estos métodos son invocados automáticamente por el
driver JDBC.
El método readSQL() permite a la instancia de EmpleadoBody
leer los atributos de su contraparte para actualizar sus propios atributos.
107
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
El método writeSQL() permite que la instancia de EmpleadoBody escriba el
valor de sus atributos en los de su contraparte.
Otro método definido en la interfaz SQLData es getSQLTypeName() que le
permite a JDBC conocer el tipo objeto al que representa. Y por último, es
necesario agregar una variable de instancia del tipo String que guardará el
nombre del tipo al que representa (pasado como parámetro en el método
readSQL).
Ejemplo: el siguiente código muestra la implementación de la clase
EmpleadoBody, que fue creada directamente en el servidor con el
predicado CREATE JAVA.
CREATE
import
import
import
import
import
import
import
AND COMPILE JAVA SOURCE NAMED EmpleadoBody as
java.sql.*;
java.io.*;
Oracle.sql.*;
Oracle.jdbc.driver.*;
Oracle.oracore.*;
Oracle.jdbc2.*;
java.math.*;
public class EmpleadoBody implements SQLData {
private String
rut;
private String
nombre;
private String
cargo;
private Date
fechaIng;
private BigDecimal sueldo;
private BigDecimal comision;
private BigDecimal anticipo;
public BigDecimal sueldoLiquido() {
BigDecimal liquido = sueldo;
if (comision != null)
liquido = liquido.add(comision);
if (anticipo != null)
liquido = liquido.subtract(anticipo);
return liquido;
}
public void aumentoSueldo(BigDecimal aumento) {
sueldo = sueldo.add(aumento);
}
// Implementacion de la interfaz SQLData
String sql_type;
public String getSQLTypeName() throws SQLException {
return sql_type;
}
public void readSQL(SQLInput stream, String typeName)
throws SQLException
{
sql_type = typeName;
108
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
rut
nombre
cargo
fechaIng
sueldo
comision
anticipo
=
=
=
=
=
=
=
stream.readString();
stream.readString();
stream.readString();
stream.readDate();
stream.readBigDecimal();
stream.readBigDecimal();
stream.readBigDecimal();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeString(rut);
stream.writeString(nombre);
stream.writeString(cargo);
stream.writeDate(fechaIng);
stream.writeBigDecimal(sueldo);
stream.writeBigDecimal(comision);
stream.writeBigDecimal(anticipo);
}
}
;
También podemos cargar la clase EmpleadoBody desde un archivo,
ejecutando la utilidad loadjava, desde el interprete de comandos, de la
siguiente manera:
>Loadjava –u scott/tiger@zorro:1521:ORCL
-v –r –t EmpleadoBody.java
El parámetros –u scott/tigre@zorro:1521:ORCL es la url de conexión
con la base de datos. El tipo se cargará en el esquema del usuario de la
conexión.
Para más información sobre la sentencia CREATE JAVA vea la referencia
bibliográfica [41], para más información sobre loadjava vea [42].
5.2.1.5.3 Implementación de métodos con C
Implementar los métodos con C es mucho más difícil que con java, porque
no existe una correspondencia directa entre tipos de Oracle y C.
Otro
problema es que los tipos primitivos de Oracle soportan valores nulos,
pero los de C no.
Para implementar los métodos con C debemos crear una biblioteca
(archivo .DLL en Windows o .so en Solaris) que contenga las funciones que
más tarde serán llamadas desde Oracle.
109
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Luego se crea un alias en el servidor que almacena la ruta externa de la
biblioteca. Por ejemplo:
CREATE LIBRARY agelib UNTRUSTED IS ’/tmp/scott1.so’;
Y finalmente definimos el tipo y la llamada a la rutina externa de C
CREATE OR REPLACE TYPE Person1_typ AS OBJECT
(
Name VARCHAR2(30),
B_date DATE,
MEMBER FUNCTION calcAge_func RETURN NUMBER
AS LANGUAGE C
NAME "age" LIBRARY agelib
WITH CONTEXT
PARAMETERS ( CONTEXT, SELF,SELF INDICATOR STRUCT,SELF
TDO, RETURN INDICATOR )
);
Para más información vea la referencia bibliográfica [30] y la [44].
5.2.1.6 Modificación de tipos (ALTER TYPE)
El predicado ALTER TYPE permite recompilar la especificación y/o el cuerpo
de un tipo objeto, también nos permite agregarle nuevos métodos.
Con
ALTER TYPE no podemos modificar o eliminar los atributos o métodos
existentes, tampoco agregar atributos [41].
La sintaxis para el predicado ALTER TYPE es la siguiente:
ALTER TYPE [schema.]type_name
{COMPILE [DEBUG] [{SPECIFICATION | BODY } ] |
REPLACE AS OBJECT (
attribute_name datatype [, attribute_name datatype]...
[{MAP | ORDER} MEMBER function_spec,]
[{MEMBER | STATIC} subprogram_spec [call_spec]
[, {MEMBER | STATIC} subprogram_spec [call_spec]]...]
)}
;
Donde:
[schema.]type_name, es el nombre del tipo a modificar
COMPILE, recompila la especificación y el cuerpo del tipo. Con las cláusulas
opcionales SPECIFICATION o BODY se puede indicar que sólo se compile la
especificación o el cuerpo.
DEBUG,
le indica al compilador de PL/SQL que genere y almacene código
para ser utilizado con PL/SQL debugger de Oracle.
110
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
REPLACE AS OBJECT( ... ), permite agregar nuevos métodos al tipo que se
está alterando.
Dentro de los paréntesis se especifica el tipo, donde
debemos incluir todos sus atributos y métodos actuales (sin ninguna
modificación) y agregar los nuevos métodos.
Ejemplos:
Para los ejemplos, tomaremos como base el tipo Empleado especificado en la
sección 5.2.1.5.1
1. Recompilación del tipo , para depuración:
ALTER TYPE Empleado COMPILE DEBUG;
2. Recompilación de la especificación del tipo:
ALTER TYPE Empleado COMPILE SPECIFICATION;
3. Recompilación del cuerpo del tipo:
ALTER TYPE Empleado COMPILE BODY;
4. Agregando método setAnticipo:
ALTER TYPE data_t REPLACE AS OBJECT
(
rut
VARCHAR2(10),
nombre
VARCHAR2(10),
cargo
VARCHAR2(9),
fechaIng
DATE,
sueldo
NUMBER(9),
comision
NUMBER(9),
anticipo
NUMBER(9),
MEMBER FUNCTION sueldo_liquido RETURN NUMBER,
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER),
MEMBER PROCEDURE setAnticipo(anticipo NUMBER)
);
En el ejemplo 4, el texto que no está en negrita, corresponde a los
atributos y métodos actuales, que se deben declarar pero no modificar.
Para crear el cuerpo para el nuevo método, se debe emplear el
predicado CREATE TYPE:
CREATE OR REPLACE TYPE BODY Empleado IS
MEMBER FUNCTION sueldo_liquido RETURN NUMBER IS
BEGIN
RETURN (sueldo + comision)-anticipo;
END sueldo_liquido;
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER) IS
BEGIN
sueldo:=sueldo+aumento;
END aumento_sueldo;
111
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
MEMBER PROCEDURE setAnticipo (anticipo NUMBER) IS
BEGIN
SELF.anticipo:=anticipo;
END setAnticipo;
END;
Como queremos remplazar la definición anterior del cuerpo, incluimos
la cláusula OR REPLACE. Junto con los nuevos métodos agregados con
el predicado ALTER TYPE debemos incluir a todos los métodos actuales.
Podemos modificar el cuerpo de los métodos actuales sin ninguna
restricción, pero no podemos modificar su especificación, porque debe
coincidir exactamente con lo descrito en ALTER TYPE. Y en CREATE
TYPE.
5.2.1.7 Eliminación de tipos (DROP TYPE y DROP TYPE BODY)
Para eliminar la especificación y el cuerpo de un tipo se utiliza la sentencia
DROP TYPE, la sintaxis es la siguiente:
DROP TYPE [schema.]type_name [FORCE] ;
Donde :
[schema.]type_name. es el nombre del tipo a eliminar
[FORCE], fuerza el borrado del tipo en el caso que existan dependencias.
Oracle marca como UNUSED todas las columnas que dependan del tipo que
ha sido borrado.
Las columnas marcadas como UNUSED son inaccesibles
[41].
Para eliminar sólo el cuerpo del tipo existe el predicado DROP TYPE BODY,
cuya sintaxis es:
DROP TYPE BODY [schema.]type_name ;
Donde :
[schema.]type_name. es el nombre del cuerpo del tipo que será eliminado.
5.2.2 Tipo Colección
112
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Un tipo colección es otro tipo de dato definido por el usuario, que nos
permite almacenar un número indefinido de elementos, todos de un mismo
tipo [31]. Un tipo colección puede ser usado para definir:
•
Una columna en una tabla relacional
•
Un atributo en un tipo objeto.
•
Variables, parámetros o tipo de retorno de una función, en PL/SQL.
En Oracle, existen dos tipos de colecciones: arreglos (VARRAYs) y tablas
anidadas (nested table).
Al igual que un tipo objeto, un tipo colección posee un método constructor
definido por el sistema, cuyo nombre es el mismo que el de la colección, y los
parámetros corresponden a los elementos que contendrá, separados por
coma, todos del mismo tipo y que, obviamente, coincide con el tipo que es
almacenado por la colección. Este constructor es una función que retorna
una nueva colección con estos valores almacenados.
Si no se pasan
parámetros, se crea una colección vacía, que es diferente de una colección
nula.
No podemos agregar métodos o atributos a un tipo colección, si lo
necesitamos, tendremos que crear un tipo objeto donde uno de sus atributos
sea del tipo colección correspondiente, junto con los atributos y métodos que
sean necesarios.
5.2.2.1 Métodos de un tipo colección.
Además del constructor, el sistema define un conjunto de métodos miembro,
que nos permitirán usar las colecciones fácilmente. Estos son [32]:
•
EXISTS(n), retorna verdadero si el elemento n existe, de lo contrario
retorna falso.
•
COUNT, retorna el número actual de elementos de la colección.
•
LIMIT, para los varray retorna el número máximo de elementos que
puede contener. Para las tablas anidadas retorna null, por no poseer
un límite.
113
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
•
FIRST y LAST, retornan el primer y el último índice de una colección
respectivamente. Al no existir elementos retorna null, si únicamente
hay uno, ambos retornan el mismo índice.
•
PRIOR(n) y NEXT(n),
retornan el índice del antecesor (PRIOR) o
sucesor (NEXT) al elemento ubicado en la posición n
•
EXTEND, EXTEND(n), EXTEND(n, i), permiten agrandar el tamaño de
una colección.
colección.
El primero, agrega un elemento null al final de la
El segundo, agrega n elementos null al final de la
colección. Y el tercero, agrega n copias del elemento de la posición i,
al final de la colección.
•
TRIM, TRIM(n), eliminan elementos desde el final de la colección.
TRIM, elimina el último elemento. TRIM(n), elimina n elementos desde
el final.
•
DELETE, DELETE(n), DELETE(m, n),
también permite eliminar
elementos, pero de una manera distinta. El primero elimina todos los
elementos de la colección.
El segundo elimina el elemento de la
posición n en una tabla anidada. Y el tercero elimina los elementos
desde m hasta n de una tabla anidada.
Estos métodos no pueden ser invocados desde sentencias SQL, sólo podemos
hacerlo desde bloques PL/SQL.
Para invocar uno de estos métodos
utilizamos la misma notación que en los tipos objeto.
5.2.2.2 VARRAY
Un arreglo (array) es un conjunto de elementos del mismo tipo, donde cada
elemento está en una posición determinada [31]. En Oracle, los arreglos son
de largo variable, por eso son denominados VARRAY. Sin embargo, debemos
indicar el máximo número de elementos que podrá contener el arreglo. La
sintaxis para un varray es la siguiente [32]:
TYPE type_name IS {VARRAY | VARYING ARRAY} (size_limit)
OF element_type [NOT NULL];
Donde:
Type_name, es el nombre del tipo de dato que el usuario está definiendo.
114
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Size_limit, es un valor (literal) entero positivo, que representa el número
máximo de elementos que puede contener el array.
Element_type, es cualquier tipo de PL/SQL con la excepción de [32]:
•
BINARY_INTEGER, PLS_INTEGER
•
BOOLEAN
•
BLOB, CLOB
•
LONG, LONG RAW
•
NATURAL, NATURALN
•
NCHAR, NCLOB, NVARCHAR2
•
Tipos Objeto con atributos BLOB, CLOB, TABLE o VARRAY
•
POSITIVE, POSITIVEN
•
REF CURSOR
•
SIGNTYPE
•
STRING
•
TABLE
•
VARRAY
Es necesario distinguir entre tamaño y límite, donde tamaño es el número de
elementos que contiene la colección, y límite que es el número máximo de
elementos que puede contener. Cuando creamos un objeto de algún tipo
varray, la cantidad de memoria asignada estará en función de su tamaño y no
de su límite. Por ejemplo, si quisiéramos crear un arreglo de puntos llamado
arr_puntos con un límite de 100 elementos, sería:
CREATE OR REPLACE TYPE arr_puntos AS VARRAY(100) OF PUNTO;
Para crear un objeto del tipo Arr_puntos, usamos su constructor de la
siguiente manera:
...Arr_puntos(Punto(3,4),Punto(5,1));
Esto creará un varray de tamaño dos, que contendrá a los puntos (3,4) y (5,1)
en las posiciones 1 y 2, respectivamente.
Si necesitamos agregar un nuevo punto a un varray existente tendremos que
aumentar el tamaño del arreglo con el método EXTEND, dentro de un bloque
PL/SQL. Por ejemplo:
...
Polilinea := Arr_puntos(Punto(3,4),Punto(5,1));
115
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Polilinea.EXTEND; -- agrego un elemento null al final.
Polilinea(3):=Punto(8,5);
...
Para eliminar el último elemento utilizamos el método TRIM,
...
Polilinea.trim;
...
No podemos utilizar los métodos delete(n) o delete(m,n) sobre un varray. Si
queremos eliminar un elemento intermedio, tendremos que desplazar a la
derecha a todos sus sucesores y luego eliminar el último elemento con el
método TRIM.
Con respecto al almacenamiento de un varray en la base de datos, este será
almacenado en línea con la fila propietaria de la colección.
Para aquellos
varrays donde el tamaño exceda los 4K, el excedente se almacenará fuera de
línea.
5.2.2.3 Tablas anidadas
Una Tabla anidada es un conjunto de elementos, sin un orden particular,
todos del mismo tipo. Ésta posee una única columna cuyo tipo puede ser un
tipo primitivo o un tipo objeto. Si es un tipo objeto, la tabla puede ser vista
también como una tabla de múltiples columnas, con una columna para cada
atributo del tipo objeto. Sintaxis para una tabla anidada es
TYPE type_name IS TABLE OF element_type [NOT NULL];
Type_name y element_type, tienen el mismo significado y restricciones que
en los varrays.
Oracle almacena una tabla anidada sin un orden particular, pero cuando
recuperamos una tabla anidada, desde la base de datos, y la almacenamos en
una variable de PL/SQL, a cada fila de la tabla se le asigna una posición o
subíndice que parte de uno (1). Esto permite acceder a la tabla anidada como
si fuera un varray, lo que simplifica su manipulación. Si manejamos la tabla
anidada desde PL/SQL podremos acceder a los métodos de la colección, de la
misma manera que con un varray.
116
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Ya vimos las semejanzas entre los varray y las tablas anidadas, ahora
veremos en qué se diferencian [32]:
•
Un varray está limitado a un máximo número de elementos, pero las
tablas anidadas no.
•
En
un
varray
no
podemos
eliminar
directamente
elementos
intermedios, pero en una tabla anidada sí.
•
Oracle almacena los datos de un varray en línea con la tabla (en la
misma tabla), pero una tabla anidada es almacenada fuera de línea, en
una tabla generada por el sistema.
•
Cuando almacenamos en la base de datos un varray, este retiene su
orden y subíndices, pero las tablas anidadas no.
•
Desde SQL, no podemos insertar, modificar o eliminar, directamente,
elementos de un varray, pero sí sobre una tabla anidada.
•
Podemos crear índices sobre tablas anidadas, pero no en un varray.
Para más información sobre tablas anidadas vea las referencias bibliográficas
[6], [30], [31], [32].
5.2.3 Encapsulamiento
Como puede ver en la sección 2.2.3
el
encapsulamiento abarca tres
aspectos:
1. Agrupar atributos y métodos en una sola entidad,
2. Distinguir entre interfaz (pública) e implementación (privada),
3. Asignar niveles de acceso individual a los atributos y métodos.
Los aspectos 1 y 2 están cubiertos en Oracle 8i, a través de los predicados
CREATE TYPE (ver 5.2.1.2.1 ) y CREATE TYPE BODY (ver 5.2.1.2.2 ).
Lamentablemente, el tercer aspecto no es soportado directamente, pero a
través de las vistas podemos restringir el acceso a los atributos.
117
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
5.2.4 Modularidad
En
Oracle
existe
una
estructura
denominada
modularidad a los programas escritos en PL/SQL.
paquete,
que
brinda
Lamentablemente, no
podemos incluir un tipo objeto en estos paquetes. Sin embargo, podemos
agrupar los tipos objeto a través de los esquemas de usuarios, logrando así la
funcionalidad de un paquete.
5.2.5 Persistencia
En todas las bases de datos relacionales la estructura encargada de persistir o
almacenar información es la tabla. En Oracle podemos persistir objetos en
columnas de tablas relacionales, o en filas de una tabla de objetos.
Una
tabla de objeto, es una clase especial de tabla que es construida en base a
un tipo objeto, donde cada fila de la tabla será una instancia de él, y cada
atributo del tipo, será una columna de la tabla [30].
Lamentablemente, si está interesado en construir una base de datos
distribuida utilizando las capacidades de replica de Oracle, no podrá replicar
las columnas de una tabla relacional que almacene objetos. Tampoco podrá
replicar una tabla de objetos.
Las operaciones básicas sobre tablas son : creación, modificación y
eliminación.
5.2.5.1 Manejo de tablas (relacionales y de objetos)
Como aclaración, no pretendemos explicar toda la sintaxis, para el manejo de
tablas, por ser muy extenso, la intención es dar una idea clara de cómo
trabajar con ellas.
5.2.5.1.1 Creación (Create Table)
Como mencionamos anteriormente, podemos definir una columna de una
tabla relacional en base a un tipo objeto. Por ejemplo: consideremos el
tipo punto definido en secciones anteriores como:
118
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
CREATE OR REPLACE TYPE
(
X
number,
Y
number,
MEMBER PROCEDURE
MEMBER PROCEDURE
MEMBER FUNCTION
);
Punto AS OBJECT
moverA(X IN number, Y IN number),
moverA(P IN Punto),
distanciaA(p IN Punto) RETURN NUMBER
Pensemos ahora que necesitamos almacenar la información de un
triangulo y su identificador, para lograr esto, creamos una tabla relacional
de la siguiente manera:
CREATE TABLE triangulo
(
id
VARCHAR2(10) CONSTRAINT pk_emp PRIMARY KEY,
A
Punto CONSTRAINT nn_A NOT NULL,
B
Punto CONSTRAINT nn_B NOT NULL,
C
Punto CONSTRAINT nn_C NOT NULL
);
Como podemos observar, la definición de tablas relacionales sigue siendo
la misma, y el tipo Punto puede ser visto como un tipo más del sistema.
Otro aspecto importante es la simplificación de la tabla triángulo al usar el
tipo punto.
Para las aplicaciones orientadas a objeto, la forma más natural de
almacenarlos es a través de tablas de objetos. Por ejemplo, consideremos
los siguientes tipos:
CREATE TYPE Empleado;
CREATE TYPE Departamento AS OBJECT (
Nombre
VARCHAR2(10),
Jefe
REF Empleado
);
CREATE TYPE Empleado AS OBJECT (
rut
VARCHAR2(10),
nombre
VARCHAR2(10),
cargo
VARCHAR2(9),
fechaIng
DATE,
sueldo
NUMBER(9),
comision
NUMBER(9),
anticipo
NUMBER(9),
depto
REF Departamento,
MEMBER FUNCTION sueldo_liquido RETURN NUMBER,
MEMBER PROCEDURE aumento_sueldo (aumento NUMBER)
);
La construcción de tablas de objetos es muy sencilla, por ejemplo,
podemos crear una tabla denominada tbl_emp para almacenar a los
119
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
empleados, y otra denominada tbl_dep para los departamentos, de la
siguiente manera:
CREATE TABLE tbl_emp OF Empleado;
CREATE TABLE tbl_dep OF Departamento;
Como puede observar, no definimos columnas para la tabla tbl_emp, ni
para tbl_dep, porque estas se definen automáticamente a partir de los
tipos Empleado y Departamento, respectivamente.
Tampoco es posible
agregar columnas adicionales.
Al
momento
de
definir
las
tablas
de
objeto,
podemos
imponer
restricciones como: NOT NULL, UNIQUE, CHECK, o definir valores por
defecto con DEFAULT sobre las columnas de una tabla de objeto, al igual
que en las tablas relacionales. Por ejemplo:
CREATE TABLE
(
CONSTRAINT
CONSTRAINT
fechaIng
CONSTRAINT
);
tbl_emp OF Empleado
rut_cons
UNIQUE(RUT),
sueldo_cons CHECK(sueldo IS NOT NULL),
DEFAULT SYSDATE,
anticipo_cons CHECK(anticipo >= 0)
Otro tipo de restricción tiene que ver con las referencias de objeto a las
cuales podemos imponer restricciones de integridad, como si fueran
claves foráneas de tablas relacionales. Por ejemplo:
CREATE TABLE tbl_emp
(
FOREIGN KEY(depto)
);
CREATE TABLE tbl_dep
(
FOREIGN KEY (Jefe)
);
OF Empleado
REFERENCES tbl_dep ON DELETE CASCADE
OF Departamento
REFERENCES tbl_emp
Cada instancia almacenada en una tabla de objeto posee un identificador
de objeto único denominado OID [31]. Este identificador permite que el
objeto almacenado pueda ser referenciado externamente, ya sea desde
otros objetos, desde columnas de tablas relacionales o desde un lenguaje
de programación como JAVA. En Oracle, podemos especificar que el OID
sea generado por el sistema o una clave primaria. Un OID generado por
el sistema es un número de 16 bytes de largo, que es único en toda la
base de datos e independiente de los valores actuales de los atributos del
objeto. Un OID basado en la clave primaria es único dentro de la tabla y
120
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
depende de los valores del objeto. El tipo de OID a utilizar se especifica al
momento de crear la tabla de objeto utilizando las palabras reservadas
OBJECT IDENTIFIER IS PRIMARY KEY u OBJECT IDENTIFIER IS SYSTEM
GENERATED. Al no especificar el tipo de OID, este será generado por el
sistema.
Por ejemplo, si queremos definir un OID del tipo clave primaria
para las instancias del tipo empleado, almacenadas en la tabla tbl_emp,
tendremos que escribir lo siguiente:
CREATE TABLE tbl_emp OF Empleado
(rut PRIMARY KEY)
OBJECT IDENTIFIER IS PRIMARY KEY;
Aunque innecesario, podemos especificar que el identificador de objeto
sea generado por el sistema, de la siguiente manera:
CREATE TABLE tbl_emp OF Empleado
OBJECT IDENTIFIER IS SYSTEM GENERATED;
Como restricción no podemos especificar un OID en una tabla relacional,
puesto que las filas no son objetos.
5.2.5.1.2 Modificación (Alter Table)
Mediante el predicado ALTER TABLE [41] podemos agregar eliminar o
modificar las columnas de una tabla relacional, pero no sobre una tabla de
objetos.
Además de alterar las columnas, el predicado ALTER TABLE
permite agregar, modificar, eliminar
o deshabilitar restricciones sobre
tablas relacionales o sobre tablas de objeto.
Por ejemplo, si queremos
eliminar las restricciones sueldo_cons y anticipo_cons
de la tabla
tbl_emp sería:
ALTER TABLE tbl_emp DROP (sueldo_cons, anticipo_cons);
5.2.5.1.3 Eliminación (Drop Table)
Para la eliminación de tablas relacionales y de tablas de objetos,
utilizamos el predicado DROP TABLE.
permiten borrar la
Las siguientes sentencias, nos
tabla relacional triangulo y la tabla de objetos
tbl_emp, creadas anteriormente
DROP TABLE triangulo;
DROP TABLE tbl_emp;
121
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Como puede observar la eliminación de una tabla de objeto es idéntica a la
de una tabla relacional.
5.2.5.2 Manejo de objetos
Luego que hayamos definido las tablas que almacenarán nuestros objetos,
podemos empezar a trabajar con las instancias.
Para esto contamos con
varios predicados que nos permitirán insertar, consultar, modificar o eliminar
objetos persistentes, que son los mismos que empleamos al trabajar con
tablas relacionales, pero que tienen algunas características nuevas, para dar
soporte al manejo de objetos. En los siguientes párrafos se describen dichos
predicados.
5.2.5.2.1 Inserción de objetos (INSERT INTO)
Para la inserción de objetos, utilizamos el predicado INSERT INTO, ya sea
al insertarlo como columna en una tabla relacional o como una fila en una
tabla de objetos.
Si quisiéramos insertar una fila en la tabla triángulo,
descrita en la sección 5.2.5.1.1 (creación de tablas) sería:
INSERT INTO triangulo
VALUES (“TR – 0001”,PUNTO(12,5),PUNTO(5,25),PUNTO(19,25));
Para aquellas columna definidas a partir de un tipo objeto, el sistema
esperará una instancia de ese tipo, al momento de pasar el valor
correspondiente a la columna. Para crearla, utilizaremos el constructor del
tipo, como en el ejemplo anterior, donde utilizamos el constructor PUNTO,
para asignarle valores a las columnas a, b, c, que representan a los
vértices del triángulo.
Para el caso de las tablas de objeto, la inserción es muy similar.
Por
ejemplo: si quisiéramos insertar un empleado a la tabla tbl_emp definida
en la sección 5.2.5.1.1 (creación de tablas) sería:
INSERT INTO tbl_emp
Values(‘13131344-6’, ‘Miguel’, ‘Ingeniero’, SYSDATE, 600000,
10000, 0,null);
122
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
El orden de los valores debe coincidir con el orden de los atributos del tipo
en el que se basa la tabla de objetos. Si un atributo está definido en base
a otro tipo objeto, será necesario utilizar el constructor respectivo, al igual
que en el primer ejemplo de esta sección (inserción de un triángulo),
pudiendo anidar constructores, cuando sea necesario.
Alternativamente,
podemos utilizar
el constructor
del tipo objeto
empleado para realizar la inserción. Lo anterior quedaría:
INSERT INTO tbl_emp
Values(
Empleado(‘13131344-6’, ‘Miguel’, ‘Ingeniero’, SYSDATE,
600000,10000, 0,null)
);
Para las columnas que sean del tipo REF, necesitaremos utilizar una
subconsulta para obtener el valor correspondiente.
Por ejemplo,
consideremos la tabla de departamentos de la sección 5.2.5.1.1 (creación
de tablas) , la inserción de una instancia de Departamento, quedaría:
INSERT INTO tbl_dep Values(
Departamento(‘Departamento de Informática’,
(SELECT REF(e) FROM tbl_emp e
WHERE e.rut = ‘13131344-6’)
)
);
Para el empleado insertado anteriormente, será necesario actualizar el
atributo depto, para que apunte al departamento correspondiente. Dicha
actualización la mostraremos, más adelante, en la sección 5.2.5.2.3
(update).
También podemos insertar objetos a partir de otra tabla, siempre y cuando
sean compatibles. Por ejemplo:
INSERT INTO tbl_emp
select value(emp) from tbl_emp2 emp
emp.nombre like ‘R%’;
En este ejemplo se copian los objetos de la tabla emp2 cuyo atributo
nombre empieza con R, pero a cada uno se le asignará un nuevo OID.
Si hacemos la inserción desde PL/SQL, podemos obtener el OID del objeto
insertado en la misma sentencia INSERT. Por ejemplo, consideremos que
123
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
queremos insertar un
objeto del tipo Empleado previamente definido,
llamado emp, en la tabla tbl_emp, y queremos guardar el OID del objeto
insertado en la variable OID_Emp que también fue previamente definida,
sería:
...
insert into tbl_emp e values(emp)
returning ref(e) into OID_emp;
...
La cláusula returning ref es muy útil cuando tenemos un objeto que
posee un atributo que es una referencia a otro, y queremos insertar ambos
objetos en una misma transacción.
5.2.5.2.2 Selección de objetos (SELECT ... FROM)
Podemos realizar consultas con el predicado SELECT sobre tablas de
objeto como si fueran tablas relacionales, donde los atributos del objeto
son las columnas de la tabla. Por ejemplo:
SELECT *
FROM tbl_emp emp
WHERE emp.sueldo >100
Aquí se obtienen todos los empleados de la tabla tbl_emp (definida en la
sección 5.2.5.1.1 ) cuyo sueldo base sea mayor a 100.
Las consultas pueden invocar a las funciones miembro de un objeto y
utilizarlas como si fueran columnas. Por ejemplo:
SELECT rut,nombre, emp.sueldoLiquido()
FROM tbl_emp emp
WHERE emp.sueldoLiquido() < 100
Este ejemplo retorna el rut, el nombre y el sueldo líquido de todos los
empleados de la tabla tbl_emp cuyo sueldo líquido es menor que 100.
Esto también es válido para las tablas relacionales con columnas definidas
a partir de un tipo objeto. Por Ejemplo:
SELECT *
FROM from triangulo t
WHERE t.a.distanciaA(b) = 100
124
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Este ejemplo entrega todos los triángulos cuyo lado AB mida 100.
La principal ventaja al usar referencias de objeto es la simplificación de las
consultas. Por ejemplo, para saber el nombre del departamento al que
pertenecen los empleados bastaría con:
SELECT rut,nombre, emp.depto.nombre
FROM tbl_emp emp;
Bajo el enfoque tradicional, sería necesario utilizar un JOIN para obtener el
nombre del departamento, pero acá basta con utilizar la referencia depto.
5.2.5.2.3 Modificación de objetos (UPDATE)
Para modificar una instancia almacenada en una tabla de objetos
utilizamos el predicado UPDATE. Por ejemplo:
UPDATE tbl_emp emp
SET emp.sueldo=emp.sueldo * 1.15
WHERE emp.sueldoLiquido() < 100
Aquí le aumentamos el sueldo base, en un 15%, a todos los empleados de
la tabla_emp (definida en la sección 5.2.5.1.1 ) cuyo sueldo líquido es
inferior a 100.
También podemos reemplazar el valor de todos los atributos del objeto
con los de otro. Por ejemplo
UPDATE tbl_emp emp
SET emp= Empleado(‘13131344-6’, ‘Miguel R.’, ‘Ingeniero’,
SYSDATE, 800000,20000, 0,null)
WHERE emp.rut =’13131344-6’
La forma más natural de modificar los atributos de un objeto es a través
de sus métodos. Lamentablemente, estos métodos no podrán invocarse
sobre objetos persistentes, debido a las restricciones impuestas por
Oracle.
Cuando explicamos la inserción de objetos, dejamos pendiente la
actualización del atributo depto que es una referencia a una instancia de
Departamento. Para realizar esta actualización sería:
UPDATE tbl_emp emp
SET emp.depto = ( SELECT REF(d) FROM tbl_dep
125
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
WHERE d.nombre =’Departamento de Informática’)
WHERE emp.rut =’13131344-6’
5.2.5.2.4 Eliminación de objetos (DELETE)
Para eliminar objetos de una tabla de objetos utilizamos el predicado
DELETE. Por ejemplo:
DELETE FROM tbl_emp emp
WHERE emp.sueldoLiquido() < 100
Aquí se eliminan todos los empleados cuyo sueldo líquido sea menor a
100.
5.2.6 Jerarquía de Clases
5.2.6.1 Asociación
Para implementar las asociaciones utilizamos las referencias de objetos. Por
ejemplo, supongamos que queremos implementar la asociación entre una
persona y una organización:
Participa
Organización
1
Persona
*
Para implementar esta relación, será necesario agregar un atributo en el tipo
objeto Persona que sea una referencia al tipo Organización.
La
implementación de los tipos quedaría:
CREATE TYPE Organizacion AS OBJECT
(
id
NUMBER,
Nombre VARCHAR2(30)
);
CREATE TYPE Persona AS OBJECT
(
rut
NUMBER,
Nombre VARCHAR2(30),
Org
REF Organizacion
);
Si la multiplicidad de la asociación fuera uno a uno, cualquiera de los tipos
puede tener la referencia al otro.
126
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Si la multiplicidad de la asociación fuera Muchos a muchos, o la asociación
en sí misma tenga atributos, será necesario crear un tipo objeto para
implementarla.
Por ejemplo, supongamos que la asociación entre una
organización y una persona fuera:
Participa
Organización
Persona
*
*
Participantes
Y quisiéramos almacenar el rol o papel que desempeña la persona en la
organización, los tipos objeto quedarían:
CREATE TYPE Organizacion AS OBJECT
(
id
NUMBER,
Nombre VARCHAR2(30)
);
CREATE TYPE Persona AS OBJECT
(
rut
NUMBER,
Nombre VARCHAR2(30)
);
CREATE TYPE Participantes AS OBJECT
(
persona
REF Persona,
Org
REF Organizacion,
Rol
VARCHAR2(50)
);
5.2.6.2 Agregación y Composición
La agregación podemos implementarla de la misma manera que una
asociación. Pero, como la asociación refleja una relación todo-parte, en la
mayoría de los casos, será más conveniente implementarla a través de un tipo
colección que almacene referencias de objetos. Por ejemplo, podemos crear
una
tabla
anidada
llamada
lista_per
que
almacene
referencias
a
participantes, y crear una columna en Organización llamada lista del tipo
Lista_per. La definición de tipos para este ejemplo quedaría:
CREATE TYPE Persona AS OBJECT
(
rut
NUMBER,
127
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
Nombre
VARCHAR2(30)
);
CREATE TYPE lista_per AS TABLE OF REF Persona;
CREATE TYPE Organizacion AS OBJECT
(
id
NUMBER,
Nombre VARCHAR2(30),
Lista lista_per
);
La composición, por su naturaleza, no debe representarse a través de
referencias de objetos, puesto que las partes sólo pertenecen a un agregado,
y se destruyen junto con él.
directamente.
En lugar de eso, utilizamos los objetos
Si el ejemplo anterior fuera una relación de agregación,
tendríamos que definir la tabla anidada lista_per como una tabla de
personas:
CREATE TYPE lista_per AS TABLE OF Persona;
Para aquellas composiciones, donde haya una asociación uno a uno el todo
contendrá un atributo del tipo de datos del tipo asociado. Por ejemplo, si
una organización tuviera una sola persona como miembro quedaría:
CREATE TYPE Persona AS OBJECT
(
rut
NUMBER,
Nombre VARCHAR2(30)
);
CREATE TYPE Organizacion AS OBJECT
(
id
NUMBER,
Nombre VARCHAR2(30),
Per
Persona
);
5.2.6.3 Herencia y Polimorfismo
En Oracle 8i La herencia no es soportada, y la única forma de polimorfismo es
la sobrecarga de métodos.
En todo caso, si necesitamos modelar relaciones de herencia, podemos
simularla a través de agregación o composición, y tendremos que dar un
soporte manual al polimorfismo. Existen varias estrategias para realizar esto,
por ejemplo, si A es la clase padre, y B, C sus subclases, podríamos crear un
128
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
tipo objeto para cada uno, donde B y C tendrían un atributo llamado super,
que sería una referencia a A, el que nos permitiría acceder a sus atributos y
métodos. El único problema con esta implementación es que no satisface
una característica esencial de la herencia, donde una instancia de B o C
también es de A, en la práctica, si tenemos una colección que almacena
instancias de A, una instancia de B debería ser posible de almacenar. Una
solución a esto es crear el tipo A como una composición, es decir, con un
atributo para cada subclase, y una variable que indique el tipo particular de la
instancia almacenada.
Este último enfoque fue empleado por Oracle para
implementar el SQL espacial [35], que es un conjunto de tipos objeto que dan
soporte a la implementación de sistemas de información geográficos.
5.2.7 Concurrencia
La concurrencia podemos verla desde dos puntos de vista:
La
•
Como un método con múltiples hilos de ejecución.
•
Como varios usuarios manipulando el mismo objeto.
concurrencia
desde
el
primer
punto
de
vista
está
resuelta,
si
implementamos el método con JAVA, puesto que este lenguaje implementa
un robusto sistema para el manejo y sincronización de múltiples hilos de
control.
Desde el segundo punto de vista, la concurrencia también es soportada,
permitiendo que varios usuarios utilicen y modifiquen el mismo objeto,
permitiendo bloqueos manuales o automáticos que garantizan la consistencia
y la integridad del objeto.
5.2.8 Manejo de Versiones de objetos y Configuraciones
Lamentablemente, Oracle no provee mecanismos para manejar versiones y
configuraciones de objetos.
129
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
5.2.9 Evolución de esquemas y de Instancias
La evolución de esquemas se refiere a la capacidad de modificar la estructura
de los tipos, agregando, modificando o eliminando métodos o atributos y que
estos cambios sean reflejados en todas las estructuras que dependan de él.
La evolución de instancia apunta a dos cosas, la primera es que al alterar un
tipo, dicho cambio debe verse reflejado en las instancias y la otra es contar
con la posibilidad de migrar instancias entre tipos.
En Oracle 8i, existe una forma restringida de evolución. A diferencia de una
tabla relacional, un tipo no puede ser alterado, solamente podemos agregar
métodos (vea 5.2.1.6 ), cambio que no afecta a los tipos, tablas o vistas que
dependen de él.
Esta carencia junto con la de herencia son las limitaciones más significativas
que tiene Oracle, Aunque con un poco más de trabajo, podremos lograr esta
funcionalidad. Una solución a este problema es crear una tabla relacional con
los atributos del objeto como columna y una vista de objeto sobre la tabla
relacional. Luego utilizaremos la vista de objeto como si fuera una tabla de
objetos, y cuando necesitemos agregar, modificar o eliminar la definición de
un atributo, lo haremos sobre la tabla relacional, y luego modificaremos
nuestra vista de objeto.
No se pueden migrar instancias entre tipos en Oracle 8i.
5.2.10 Transacciones y recuperación ante fallos.
Estas características están presentes en Oracle desde varias versiones atrás, y
de hecho son uno de sus puntos más fuertes.
Una transacción, es una unidad lógica de trabajo que contiene una o más
sentencias SQL que pueden ser todas aplicadas a la base de datos o ninguna.
La utilidad de una transacción es que nos permite impedir que los cambios
producidos por las sentencias SQL ya ejecutadas se apliquen a la base de
130
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
datos, al ocurrir alguna excepción, manteniendo así la consistencia y la
integridad.
En lo referente a la recuperación ante fallos, existen varios errores que Oracle
soluciona automáticamente y otros requieren de una mínima intervención del
usuario.
Otra característica importante, es que la mayoría de los fallos
pueden ser superados sin la necesidad de bajar el servidor.
5.2.11 Mecanismos de autorización
Al igual que en SQL:1999, los mecanismos de autorización están basados en
las tablas y en los tipos objeto.
Se autoriza o restringe el acceso y
manipulación de las tablas o tipos objeto, pero no se puede restringir el
acceso sobre un objeto o una fila.
5.2.12 Compatibilidad con el modelo relacional
Oracle posee una alta compatibilidad con el modelo relacional, permitiendo
que interactúen las estructuras relacionales con las nuevas estructuras.
Además permite la creación de vistas de objeto sobre tablas relacionales.
Una vista de objetos, se basa en el resultado de una consulta y en un tipo
objeto, que definirá las columnas de la vista. La consulta pude estar basada
en varias tablas, sean relacionales o de objeto.
Al consultar una vista de
objetos, se obtendrá un conjunto de instancias del tipo objeto en el que se
base la vista.
Por ejemplo: supongamos que una empresa posea una tabla que almacena a
todos sus departamentos, y que fue creada de la siguiente manera:
CREATE TABLE departamento (
ID_Dep
NUMBER (10) NOT NULL PRIMARY KEY,
Nombre
VARCHAR2 (50)
);
Para crear una vista de objetos de esta tabla, primero tendremos que crear un
tipo objeto cuyos atributos serán las columnas de la tabla departamento, y
luego podremos crear nuestra vista de objeto.
131
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
CREATE TYPE dep_T (
ID_Dep
NUMBER,
Nombre
VARCHAR2 (50)
);
CREATE VIEW dep_ObjView OF dep_T
WITH OBJECT OID (ID_Dep)
AS SELECT ID_Dep, Nombre FROM DEPARTAMENTO;
Al crear la vista, debemos indicar que cree el OID de los objetos a partir de
la clave primaria de la tabla relacional.
Crear esta clase de vistas permite acceder a toda la capacidad del manejo de
objetos, como invocación de métodos y referencias a objetos, sin tener que
migrar los datos de las tablas relacionales.
5.2.13 Limitaciones encontradas en Oracle 8i
En Oracle 8i, encontramos las siguientes limitaciones, referente al manejo de
objetos:
•
Un tipo no puede tener más de 1000 atributos
•
No podemos sobrecargar el constructor definido por el sistema, ni
redefinirlo. Tampoco podrá crear nuevos constructores.
•
Los procedimientos miembro de un tipo, no pueden ser invocados
desde SQL.
•
Las funciones miembro de un tipo, que posean uno o más parámetros
pasados como INOUT o OUT, no pueden ser invocados desde SQL.
•
No podemos modificar la definición de atributos o métodos existentes
de un tipo objeto. Sólo podemos agregar nuevos métodos.
•
No podemos replicar tablas de objetos.
•
No podemos tener colecciones que almacenen colecciones, ni
colecciones de objetos que posean un atributo de un tipo de
colección.
•
No podemos definir colecciones en base a ciertos tipos de datos como
por ejemplo: BOOLEAN, BLOB, CLOB, LONG, LONG RAW, y otros.
•
No podemos especificar un nivel de encapsulamiento (private, public,
protected) para los atributos, ni para los métodos.
•
No podemos definir Jerarquías de Herencia, ni simple, ni múltiple.
132
Oracle 8i y la orientación a objeto - Soporte a la orientación a objeto
•
No podemos duplicar las tablas de objeto en Oracle 8i.
133
5.3 Evaluación
En este capítulo evaluaremos la implementación que hace el SABD Oracle 8i
del paradigma de la orientación a objeto, utilizando los mismos criterios de la
evaluación del estándar SQL:1999.
El objetivo de esta evaluación es
determinar en que porcentaje son soportadas las características de la
orientación a objeto (ver 2) y los requerimientos para las bases de datos
orientadas a objeto (ver 3.1.2.1), por parte del SABD Oracle 8i. Junto con
ello, agregaremos la evaluación realizada para el estándar SQL:1999, para
facilitar su comparación.
5.3.1 Criterios de evaluación
Para la evaluación del soporte dado por Oracle 8i a la Orientación a Objeto,
utilizaremos los mismos criterios y la misma valoración utilizada en el
capítulo anterior para evaluar SQL-1999. Estos son:
1. Definición de tipos o clases
a. Definición de atributos estáticos
b. Definición de atributos de instancia
c. Constructores definidos por el usuario
d. Métodos estáticos
e. Métodos de instancia
f.
Sobrecarga de métodos
g. Definición de colecciones
h. Clases abstractas
2. Encapsulamiento
a. Atributos y métodos en una sola entidad
b. Distinguir entre interfaz e implementación
c. Visibilidad de métodos (Ej.: Public, private, protected)
d. Visibilidad de atributos (Ej.: Public, private, protected)
3. Modularidad
4. Jerarquía de clases o tipos
a. Asociación
134
Oracle 8i y la orientación a objeto – Evaluación
b. Agregación y Composición
c. Herencia Simple
d. Herencia Múltiple
e. Polimorfismo
5. Concurrencia
a. Métodos con múltiples hilos de control
b. Concurrencia de usuarios.
6. Persistencia de objetos
a. Creación
b. Modificación
c. Eliminación
d. Consulta
e. Identificadores de objetos
7. Versiones y configuraciones de objetos
8. Evolución de instancias
9. Evolución de esquemas
a. Agregar Atributos
b. Agregar Métodos
c. Agregar Restricciones sobre objetos persistentes
d. Eliminar Atributos
e. Eliminar Métodos
f.
Eliminar Restricciones
g. Modificar definición de atributos
h. Modificar Interfaz de métodos
i.
Modificar Implementación de métodos
j.
Modificar Restricciones
k. Deshabilitar y habilitar restricciones
10. Transacciones y recuperación ante fallos
11. Mecanismos de autorización basados en objetos
12. Compatibilidad con el modelo relacional.
Si la característica...
Está presente
No está presente, pero se puede simular
No está presente
Valoración
100%
60%
0%
135
Oracle 8i y la orientación a objeto – Evaluación
5.3.2 Matriz de evaluación
Valoración
Oracle 8i
SQL:1999
85%
a. Definición de atributos estáticos
95%
60%
60%
100%
100%
60%
100%
d. Métodos estáticos
100%
100%
e. Métodos de instancia
100%
100%
f.
100%
100%
100%
100%
60%
100%
b. Definición de atributos de instancia
c. Constructores
definidos
por
el
Final
Parcial
1. Definición de tipos o clases
Final
Parcial
Características
Valoración
usuario
Sobrecarga de métodos
g. Definición de colecciones
h. Clases abstractas
2. Encapsulamiento
80%
a. Atributos y métodos en una sola
80%
100%
100%
e
100%
100%
c. Visibilidad de métodos (Ej.:Public,
60%
60%
60%
60%
entidad
b. Distinguir
entre
interfaz
implementación
private, protected)
d. Visibilidad de atributos (Ej.: Public,
private, protected)
3. Modularidad
60%
60%
4. Jerarquía de clases o tipos
82%
92%
a. Asociación
100%
100%
b. Agregación y Composición
100%
100%
c. Herencia Simple
60%
100%
d. Herencia Múltiple
60%
60%
e. Polimorfismo
60%
100%
5. Concurrencia
100%
100%
136
Oracle 8i y la orientación a objeto – Evaluación
a. Métodos con múltiples hilos de
100%
100%
100%
100%
control
b. Concurrencia de usuarios.
6. Objetos Persistentes
100%
100%
a. Creación
100%
100%
b. Modificación
100%
100%
c. Eliminación
100%
100%
d. Consulta
100%
100%
e. Identificadores de objetos
100%
100%
7. Versiones
y
configuraciones
de
0%
0%
8. Evolución de instancias
0%
60%
9. Evolución de esquemas
80%
92%
objetos
a. Agregar Atributos
60%
100%
b. Agregar Métodos
100%
100%
c. Agregar Restricciones sobre objetos
100%
100%
d. Eliminar Atributos
60%
100%
e. Eliminar Métodos
60%
100%
100%
100%
g. Modificar definición de atributos
60%
60%
h. Modificar Interfaz de métodos
60%
60%
100%
100%
100%
100%
persistentes
f.
i.
Eliminar Restricciones
Modificar
Implementación
de
métodos
j.
Modificar Restricciones
10. Transacciones y recuperación ante
100%
100%
60%
60%
100%
100%
70,58%
78,25%
fallos
11. Mecanismos de autorización basados
en objetos
12. Compatibilidad
con
el
modelo
relacional.
Promedio
137
6 Una Aplicación de ejemplo
6.1 Introducción
En este capítulo se describirá un prototipo desarrollado bajo el paradigma de
la orientación a objeto, utilizando como lenguaje a Java y Oracle 8i para hacer
persistir a los objetos.
El prototipo esta relacionado con la gestión de recursos hídricos, tema que, a
juicio personal, es muy interesante y complejo a la vez. Por esta razón y para
una mejor comprensión del prototipo que expondremos más adelante,
veamos primero lo siguiente.
6.1.1 Importancia del recurso hídrico [29]
El mundo cuenta con grandes reservas de agua dulce, sobre 37 millones de
Km3, que exceden cualquiera necesidad imaginable de la población humana,
como por ejemplo los siguientes usos: riego, agua potable, generación de
energía industrial y minería, navegación, recreación, control de calidad,
control de crecidas, protección y conservación del medio ambiente, bebida
animal, refrigeración de plantas nucleares, turismo, etc.
Sin embargo, la mayor parte del recurso no nos es accesible, ya que más de
las tres cuartas partes de las reservas se encuentran retenidas en los
glaciares y en el hielo polar, y el resto muestra una distribución irregular de
un lugar a otro y de una estación a otra.
Es por lo anterior, que en la mayoría de las regiones del planeta sólo se
puede alcanzar un nivel de aprovechamiento adecuado y rentable mediante
una planificación y una gestión activa de los recursos hídricos.
Aunque el agua cae del cielo, no es gratuita, y la intervención del hombre en
un ciclo natural acarrea siempre un costo, precio que a veces resulta muy
caro.
139
Una aplicación de ejemplo - Introducción
La planificación de los recursos hídricos tiene por objetivo fundamental dar el
máximo aprovechamiento al recurso en forma integral.
6.1.2 Gestión del recurso hídrico en Chile
La Dirección General de Aguas (DGA) del Ministerio de Obras Públicas de
Chile (MOP) es la encargada de planificar y gestionar los recursos hídricos con
los que cuenta el país. Los objetivos de carácter general de la planificación de
los recursos hídricos son [29]:
Perfeccionar las técnicas de control y manejo del agua.
Desarrollar y mejorar los métodos para conservar y aumentar las
disponibilidades de agua en cantidad y distribución temporal.
Desarrollar y mejorar los métodos de control de contaminación, de
modo de proteger y mejorar la calidad de los recursos hídricos.
Desarrollar y mejorar los métodos y la eficiencia de la recolección
de los datos de terreno necesarios para lograr una adecuada
planificación y diseño de las obras de aprovechamiento del agua.
Desarrollar y mejorar los métodos de evaluación de los desarrollos
de los recursos hidráulicos de modo de obtener una maximización
de los beneficios socioeconómicos netos.
Para llevar a cabo su tarea, la DGA necesita contar con herramientas que le
permitan hacer pronósticos acertados, y predecir por ejemplo lo que
sucederá al intervenir el cause de un río con algún nuevo proyecto (embalse,
central hidroeléctrica, canales, etc).
Algunas de estas herramientas
corresponden a los modelos de simulación2 hidrológica operacional [29],
los cuales representan los fenómenos hidrológicos en una cierta cuenca3,
además, incorporan todas las obras hidráulicas existentes o futuras.
2
3
La técnica de reproducir la esencia de un sistema sin reproducir el sistema en si
Territorio cuyas aguas afluyen todas a un mismo río, lago o mar
140
Una aplicación de ejemplo - Introducción
6.1.3 Modelación de cuencas y proceso de Simulación
hidrológico operacional4.
Para facilitar el proceso de simulación, existen modelos de tipo general que
se caracterizan por tener previamente definidas las rutinas típicas de la
simulación, de modo que el usuario sólo realiza lo siguiente [29]:
•
Definición de topología
•
Ingreso de datos para cada elemento del modelo
•
Procesar
Para realizar la simulación es necesario contar con un modelo de la cuenca
que nos interesa analizar (Definición de topología),
La cual es modelada a
través de un conjunto interconectado de objetos cada uno de los cuales
representa un elemento hidráulico de la cuenca.
Existen dos tipos de
objetos: Fijos y Variables [29].
Los objetos fijos, tienen una ubicación preestablecida, que no se puede
modificar, como tampoco sus atributos, porque estos objetos definen la
topología básica de la cuenca (al modificarse dejan de modelar la cuenca).
Los objetos fijos son los ríos o causes naturales más importantes y los Nodos
o lugares donde confluyen aportes o extracciones de caudales. En los nodos
se realiza un operación matemática denominada balance de caudal, cuya
fórmula general es:
Entrada – Salida = Variación de almacenamiento.
Dos nodos consecutivos dentro de un mismo río definen los tramos de río.
Por los tramos de ríos de la cuenca es por donde se mueven los caudales de
un nodo a otro según la dirección del flujo [29].
4
En esta sección no pretendemos enseñar a modelar cuencas reales, sólo dar los conocimientos
básicos para el diagrama de una cuenca modelada.
Tampoco se verá en forma detallada el
proceso de simulación
141
Una aplicación de ejemplo - Introducción
Considerando solamente los objetos fijos (ríos y nodos) podríamos tener un
esquema de la modelación de una cuenca como el siguiente (figura 6) :
Simbología:
: Nodo
: Tramo de Río
figura 6 : Esquema de una cuenca en base a ríos y nodos
Por su parte los objetos variables son posibles de ubicar en cualquier nodo y
modificar sus atributos.
Los objetos variables corresponden a diferentes
elementos hidráulicos cuya función puede ser extracción, aporte, conducción,
consumo, generación o regulación de caudales. Estos son [29]:
•
Aporte natural: Aporte de caudales a un nodo.
•
Canal: Permite la conducción de un
caudal máximo entre dos
nodos. (Son creados por el hombre).
•
Hoya intermedia: Aporte de caudales a un nodo que corresponden
a aquellos caudales que son aportados a un tramo de río al cual el
nodo pertenece. Esto se debe a que en el modelo las entradas o
salidas de caudales sólo se pueden hacer en un nodo.
•
Central hidroeléctrica: Realiza una captación de agua desde un
nodo inicial, genera energía eléctrica y entrega los caudales a un
nodo final sin consumo.
•
Embalse: Obra
de
regulación
de
caudal
que
permite
el
almacenamiento de agua.
•
Zona de riego: Centro de demanda consuntiva de agua para el
sector agrícola.
•
Captación de agua potable: Extracción de agua potable para el
consumo.
•
Captación de uso industrial o minero: Extracción de agua para
consumo Industrial o minero
•
Descarga contaminante: Aporte de caudales (contaminados) a un
nodo.
142
Una aplicación de ejemplo - Introducción
•
Recuperación en el cauce: Punto donde se ha verificado una
recuperación de caudal en un río, que se supondrán concentradas
en un nodo específico.
•
Pérdida en el cauce: Punto donde se ha verificado una pérdida de
caudal en un río,
que se supondrán concentradas en un nodo
específico.
Ya explicamos todos los objetos que intervienen en el modelo de una cuenca,
sólo falta agregar, que estas se pueden dividir en sectores.
La figura 7 corresponde a un modelo real: La cuenca del río Maule, que por
motivos de espacio, sólo se mostrará el sector uno de dicha cuenca
(aproximadamente el 10% del diagrama total). En ella podemos apreciar la
mayoría de los objetos aquí descritos.
Este diagrama fue desarrollado por la Dirección General de Aguas del
Ministerio de Obras Públicas.
143
Una aplicación de ejemplo - Introducción
Simbología
Nodo
Nodo
coincidente
con estación
pluviométrica
Río o Estero
Embalse
C
Central
Hidroeléctrica
Proyectada
C
Central
Hidroeléctrica
Canal Principal
Derrames
Zona de Riego
Abreviaturas
HI = Hoya Intermedia
F
= Filtraciones
R
= Rebases
Ee = Entregas para
Energía
Er = Entregas para
Riego
G
= Entregas generables
por central Hidro.
RN = Régimen Natural
figura 7: Sector uno del esquema de la modelación de la cuenca del río Maule [29]
144
Una aplicación de ejemplo - Introducción
6.1.3.1 Simulación
Para realizar la simulación hidrológica en la cuenca del río Maule, la DGA
cuenta con un programa computacional, el cual toma como base información
estadística, las modificaciones hechas por el usuario, como por ejemplo
agregar un embalse, y un rango de años que indican el período de
simulación.
La unidad mínima en este modelo es el mes, puesto que todas
las estadísticas de caudales se encuentran en esta unidad de tiempo. La
simulación comienza desde aguas arriba hacia aguas abajo, nodo por nodo.
En cada uno de los nodos se consideran todos los caudales de entrada y se
distribuye el agua por todas las salidas del nodo, las cuales en algunos casos
pasarán a ser entradas de otros nodos. Cada vez que se recorre el modelo
completo, se pasa al siguiente mes de simulación. El algoritmo de simulación
es el siguiente
Inicio
Para cada año de simulación haga
Para cada mes
Para cada nodo del modelo haga
Operar Objetos que aportan caudal
Distribuir caudales
Opera embalses
Balance hidrológico en el nodo
Fin Para cada nodo
Resultados de operación mensual
Fin Para cada mes
Resultados de operación anual
Fin Para cada año
Fin
Además existe un proceso de simulación especial llamado simulación de
temporada octubre a marzo [29].
Para desarrollarla se pronostican los
caudales medios mensuales de cada uno de los objetos del modelo
denominados “Hoya Intermedia” (H.I.) y Régimen natural (R.N), para cada uno
de los meses de octubre a marzo del año en que se hace la simulación.
Estos pronósticos, más los cambios en el modelo, son los datos de entrada
para la simulación, la que es idéntica a la anterior, salvo que esta tiene un
período fijo.
145
6.2 Descripción del Prototipo
El prototipo consiste en una aplicación que implementa una versión reducida
del modelo de simulación hidrológico operacional de tipo general, descrito en
la sección anterior, realizando únicamente la simulación de temporada, para
una cuenca que contemple los siguientes objetos:
Nodos
Ríos y tramos de río
Embalses
Central Hidroeléctrica de pasada
Canal Principal
Hoya Intermedia
Régimen Natural
Captación de agua potable
A partir de estos objetos podemos simular una cuenca como la mostrada en
la sección anterior (sector 1 de la cuenca del río Maule) si a esta
excluyéramos las zonas de riego, los derrames y los nodos coincidentes con
estación pluviométrica.
Los requerimientos del prototipo son:
Implementar una interfaz de usuario gráfica para mostrar el esquema
de la cuenca
Permitir la consulta de cualquier objeto de la cuenca pudiendo ser
antes o después de la simulación.
Realizar el proceso de simulación de temporada el que tendrá como
salida un informe con los caudales medios mensuales para cada
elemento (objeto) de la cuenca, en cada mes de simulación.
Responder a consultas como:
1. Embalses bajo sus volúmenes mínimos y rebasados.
2. Energía generada.
146
Una aplicación de ejemplo – Descripción del prototipo
6.2.1 Descripción de los objetos soportados
Para todos los objetos de la cuenca es necesario almacenar los atributos que
describen su ubicación y el caudal para cada mes de la simulación. Cabe
destacar que esta aplicación debe mostrar el esquema de una cuenca y no
una cuenca, por esto, los datos de ubicación son en el plano cartesiano y no
coordenadas terrestres como sucede en las aplicaciones SIG. Otro aspecto a
considerar, es que la simulación de temporada está basada en demandas y no
en derechos de agua, por esta razón, no es necesario almacenar la
información referente a los derechos.
6.2.1.1 Nodos.
El nodo es un objeto de tipo fijo, es decir que su ubicación y definición no es
posible de alterar en el modelo una vez que se ha definido. En cada nodo es
posible colocar cualquier objeto, a sola excepción de los cauces naturales
que son fijos.
Cada nodo representa un lugar de la cuenca donde confluyen aportes y
extracciones, de modo que es posible efectuar un balance de caudales. Sólo
en los nodos se puede efectuar balances hídricos en este modelo.
Para individualizar cada nodo, cada uno de ellos se denomina con dos
números separados por un guión. El primer número representa el sector, en
tanto que el segundo corresponde al número correlativo dentro del sector,
esto es útil cuando se tiene una cuenca dividida en subcuencas o sectores.
Cabe destacar que el número correlativo dentro del sector se debe definir de
modo que todos los caudales afluentes y extracciones estén determinados
previamente, para efectuar el respectivo balance hídrico. De este modo, se
puede definir la secuencia de los balances en los nodos, utilizando el
mencionado número correlativo.
147
Una aplicación de ejemplo – Descripción del prototipo
Esquema
i-j
Información que se desea almacenar
Código del nodo, que se indica como 'NO i-j", donde 'i" es el número
del sector, 'j" es el número correlativo del nodo en el sector.
Cota del nodo.
6.2.1.2 Ríos y tramos de río.
Este es un objeto de tipo fijo al igual que los nodos. Corresponde a los ríos,
esteros o cauces naturales en general, los cuales pueden atravesar por varios
nodos en su trayecto. Dependiendo del número de nodos por los cuales pase
el río, se definen tramos, que se designan en forma correlativa, desde aguas
arriba hacia aguas abajo.
En el modelo de simulación, este es un objeto que permite la conducción del
caudal entre un nodo inicial y un nodo final, sin restricción de capacidad de
conducción.
Esquema
En el esquema, el rió se indica con una línea de trazo más grueso.
i-j
Rio XXXX (Tramo K)
m-n
Información que se desea almacenar
Código del río
Nombre del río
Tramos del río,
Nodo inicial y nodo final.
148
Una aplicación de ejemplo – Descripción del prototipo
6.2.1.3 Embalses.
Este objeto representa una obra de regulación de caudal, que puede tener
varias entradas, tales como una hoya aportante o caudales en régimen
natural, como también canales alimentadores. El objeto embalse contempla
cinco tipo de salidas diferentes, a saber:
Filtraciones (F)
Entregas para energía, sin generar (Ee)
Entregas para riego (Er)
Rebases (R)
Caudal Generado (G)
El objeto embalse se ubica en un cierto nodo, pero cada una de sus salidas
puede definirse en nodos diferentes.
EV
Esquema
F
R
Ee
Er
G
Abreviaturas:
Ev: Evaporación del embalse
R : Rebases
Ee: Entrega para energía (sin generar)
Er: Entrega para riego
G : Caudal generado en el embalse (central a pié de presa).
F : Filtraciones del embalse.
Información que se desea almacenar
Código del objeto
Nodo
149
Una aplicación de ejemplo – Descripción del prototipo
Capacidad máxima del embalse (volumen útil), en millones de metros
cúbicos.
Evaporación bandeja mensual, en milímetros.
Valores de superficie (hectáreas) y volúmenes (millones de metros
cúbicos).
Coeficiente de embalse. (Normalmente se utiliza 0,7).
Valores de caudal máximo posible de entregar por válvulas en m3/s y
volumen almacenado en millones de m3. (para verificación de entrega
máxima del embalse).
Valores de filtración en litros por segundo y volumen del embalse, en
millones de metros cúbicos.
Nodos de llegada de cada una de las salidas del embalse. (Son 5
valores)
Capacidad máxima de conducción de las entregas Er (riego), Ee
(energía) y G (generada).
Volumen inicial del embalse, en el primer mes de la simulación, en
millones de metros cúbicos.
Curva de alerta. Consiste en la definición de los volúmenes mínimos
que debe tener el embalse en cada mes, como condición deseable. Si
no se incluye este dato, no se verificará esta restricción de curva de
alerta.
6.2.1.4 Central Hidroeléctrica de pasada
Este objeto representa una central hidroeléctrica de pasada, que capta sus
aguas desde un nodo inicial y las entrega a un nodo final, sin consumo de
agua.
Esquema
i-j
C
m-n
Información que se desea almacenar
Código del objeto
Nodo inicial.
Nodo Final.
150
Una aplicación de ejemplo – Descripción del prototipo
Caudal máximo de generación en m3/s.
Caudal mínimo medio anual, en m3/s.
6.2.1.5 Canal Principal
Este objeto permite la conducción de un caudal máximo, con una eficiencia
de conducción dada, entre dos nodos.
Esquema
En el esquema, el objeto “canal" se representa a través de una flecha con
trazo doble, que indica el sentido del escurrimiento.
Canal Principal
i-j
i-j
Información que se desea almacenar
Código del objeto
Denominación del canal
Nodo inicial
Nodo final o punto de llegada
Capacidad de conducción en m3/s
Eficiencia de conducción en porcentaje.
Parámetros ‘a’, ‘b’ y ‘c’ de la captación del canal en un cauce natural y
que representa el caudal posible de captar por el canal en función del
caudal del río, según se indica en la figura siguiente :
CAUDAL CAPTADO (m3/s)
a
CAUDAL DEL RIO(m3/s)
b
c
151
Una aplicación de ejemplo – Descripción del prototipo
6.2.1.6 Hoya Intermedia
Corresponde a una estadística de caudales medios mensuales, que ingresan o
aportan al nodo y representan el aporte de la hoya intermedia de un río o
cauce natural entre dos nodos.
Esquema
H.I.
i-j
Información que se desea almacenar
Código del Objeto
Denominación de la Hoya Intermedia o nombre del río
Código del Nodo
Estadística de caudales.
Código del río al cual aporta la H.I.
6.2.1.7 Régimen Natural
Corresponde a una estadística de caudales medios mensuales, en régimen
natural, que ingresan o aportan al nodo.
Esquema
R.N
i-j
Información que se desea almacenar
Código del objeto
Denominación de los aportes
Nodo
Estadística de caudales.
152
Una aplicación de ejemplo – Descripción del prototipo
6.2.1.8 Captación de Agua Potable
Este objeto representa una extracción de agua potable desde un nodo, para
el consumo.
Requiere los valores de caudales medios mensuales de las
extracciones.
Esquema
i-j
A.P.
Información que se desea almacenar
Código del Objeto
Código del Nodo
Caudales de extracción medio mensual
153
6.3 Diseño del prototipo
Para el diseño del prototipo utilizamos la notación UML, pero no completa,
solamente los diagramas de clases y los diagramas de colaboración. Para los
lectores no familiarizados con UML en el apéndice B encontrará una breve
descripción.
Una aclaración importante, por falta de información y de
tiempo, no fue posible encontrar información sobre la correcta operación de
un embalse, y la fórmula con la que se convierte un caudal a kilo watt. Por lo
tanto, estos dos aspectos del prototipo están desarrollados a partir de una
fórmula incorrecta, por lo tanto los resultados que pueda entregar el modelo
de simulación, serán incorrectos.
En todo caso bastaría con corregir los
métodos que incorporan dichas fórmulas y el modelo quedaría correcto.
Tenga en cuenta que el objetivo de este prototipo es probar las capacidades y
limitaciones de Oracle 8i para el manejo de objetos y como interactúa este
con Java y no dar una solución acabada y óptima para el problema planteado.
6.3.1 Diagramas de clases
6.3.1.1 Clases implementadas en Oracle 8i
Comenzaremos analizando el conjunto de clases que representa a los objetos
de la cuenca, y que serán creadas en Oracle 8i para hacer persistir a los
objetos.
Para cada uno de los objetos de la cuenca soportados por el prototipo,
crearemos una clase. De este modo tenemos las siguientes:
Nombre de la Clase Descripción
Cuenca
Representa a una cuenca
Nodo
Representa a un nodo de la cuenca
Río
Representa un Río de la cuenca
Embalse
Representa a un embalse de la cuenca
Salida_Emb
Representa a los flujos de salida de un embalse
Regimen_Natural
Representa a un Régimen Natural
154
Una aplicación de ejemplo – Diseño del prototipo
Hoya_Inter
Representa a una Hoya Intermedia
Cap_Agua_Pot
Representa una Captación de agua potable
Central_hidro
Representa una Central Hidroeléctrica
Canal
Representa un Canal
Representa un tramo de Río, que transporta un
Tramo
caudal desde un nodo inicial a un nodo final
Al analizar el problema, descubrimos que existe un conjunto de clases que en
términos generales son Flujos de caudales que aportan y/o extraen caudales
de un nodo.
A partir de esto construimos el siguiente esquema de
generalización:
Flujo
Aportante
Salida_Emb
Regimen_Natural
Extraccion
Hoya_Inter
Cap_Agua_Pot
Apor_extrac
Central_Hidro
Canal
Tramo
Además de la jerarquía de generalización mostrada anteriormente, existen
otras relaciones entre las clases. Estas relaciones son:
•
Un Río posee uno o muchos tramos
•
Un embalse esta ubicado en un único nodo
•
Un Embalse posee siempre cinco flujos de salida
•
Un nodo posee uno o muchos flujos de entrada que le aportan
caudales, y uno o muchos flujos de salida que le extraen caudales.
•
Dependiendo del tipo de flujo, éste puede poseer un nodo inicial, de
donde extrae un caudal y un nodo final a donde aporta un caudal. El
nodo inicial debe ser distinto al final, y un flujo debe poseer por lo
menos un nodo (sea inicial o final).
155
Una aplicación de ejemplo – Diseño del prototipo
El siguiente diagrama muestra dichas relaciones:
entrada
Tramo
1..*
Flujo
Aporta
1..*
0..1 Nodo_Inicial
Salida 1..*
Extrae
Nodo_Final
1
5
1
*
Está
0..1
1
Rio
Nodo
0..1
Salida_Emb
Embalse
1
Cuenca
Una cuenca es un conjunto de nodos, flujos, embalses, etc, pero como todos
estos objetos están enlazados directa o indirectamente con el nodo,
podemos representar una cuenca como un conjunto de nodos.
El conjunto de clases mostrado hasta ahora corresponde a las abstracciones
del dominio del problema, cuyos objetos deberán ser almacenados en la base
de
datos.
El
siguiente
diagrama
muestra
las
clases
a
nivel
de
implementación, incluyendo los atributos y métodos para cada clase.
Además de otras clases necesarias para la implementación. El tipo de dato
de los atributos corresponde a los tipos de Oracle.
156
Una aplicación de ejemplo – Diseño del prototipo
Como la razón de ser de este prototipo es evaluar las capacidades de Oracle
8i en el soporte de objetos, la simulación es ejecutada directamente en el
servidor.
La clase arr_caudales, almacena los caudales para cada uno de los meses de
la simulación (6 meses, de octubre a marzo).
Las clases Graf_nodo y
Graf_cuenca, forman parte la jerarquía de clases definidas para describir la
geometría de cada uno de los objetos
del diagrama de la cuenca.
El
siguiente Diagrama de clases muestra dicha jerarquía :
157
Una aplicación de ejemplo – Diseño del prototipo
Como Oracle8i, no implementa la herencia, tuvimos que simularla a través
de la composición.
La estrategia utilizada fue incluir en la superclase un
atributo para cada una de sus subclases, junto con otro que indicara el tipo
actual del objeto. Esto nos permite dar soporte a la substituibilidad de tipos,
es decir, permitir que donde se espere una instancia de una superclase,
también sea válida una instancia de la subclase.
La misma estrategia
utilizamos para implementar la jerarquía de herencia de la clase flujo.
El
siguiente diagrama muestra dicha implementación
158
Una aplicación de ejemplo – Diseño del prototipo
El código necesario para implementar todas estas clases en Oracle 8i, se
encuentra en el anexo C.1, junto con ello, una explicación del tipo, de sus
atributos y métodos.
159
Una aplicación de ejemplo – Diseño del prototipo
Para almacenar los objetos, se crearon cinco tablas, estas son:
•
Tbl_Cuenca. Almacena objetos del tipo Cuenca
•
Tbl_Rio. Almacena objetos del tipo Río
•
Tbl_Nodo. Almacena objetos del tipo Nodo
•
Tbl_Flujo. Almacena objetos del tipo Flujo
•
Tbl_Emb. Almacena objetos del tipo Embalse
Como puede observar, no es necesario crear una tabla para cada subclase del
tipo flujo. Esto se debe a que el tipo flujo encapsula a todas las subclases.
El código para la implementación de estas tablas en Oracle 8i se encuentra en
el anexo C.2. Ahí también encontrará un ejemplo de inserción para cada uno
de los tipos existentes.
160
Una aplicación de ejemplo – Diseño del prototipo
6.3.1.2 Clases implementadas en Java
Existe una utilidad llamada JPUB (Java Publisher) [34] que permite exportar los
tipos creados en Oracle 8i a Java. Por cada tipo objeto, esta utilidad crea dos
clases java, una para almacenar referencias al objeto y otra para almacenar al
objeto. Este conjunto de clases permiten el intercambio de objetos entre Java
y Oracle en forma transparente.
Por ejemplo, para exportar el tipo
apor_extrac definido en Oracle a Java sería:
$ jpub –user=scott/tigre –sql=apor_extrac:AporExtracOra
Esto genera las clases AporExtracOra.java y AporExtracOraRef.java,
descritas en los anexos C.4.4.1 y C.4.4.2, respectivamente.
Para desarrollar el prototipo, lo primero fue generar las clases java con JPUB,
las cuales fueron agrupadas en el paquete objcuenca. Para eso fue necesario
agregar una línea de código (package objcuenca;) a cada una de las clases.
En C.4.4 encontrará una lista completa de las clases generadas con JPUB para
el prototipo.
Para mostrar visualmente cada uno de los objetos de la cuenca, definimos la
Interface Graficable y una clase para la superficie de dibujo llamada
LienzoCuenca.
JPanel
LienzoCuenca
-lasFiguras : Vector
-zoom : int
+addFigura(f : Graficable) : void
0..*
+buscarFigura(x : int, y : int) : Graficable
+clearFiguras() : void
+dibujarFiguras(g : Graphics ) : void
+getZoom() : int
+setZoom(zoom : int) : void
+paint(g : Graphics) : void
+reloadFiguras() : void
+setVectorFiguras(f : Vector) : void
«Interface»
Graficable
1..*
+dibujar(d : Dibujante) : void
+dimensionMinima() : Dimension
+dlgAtributos() : void
+getZoom() : int
+loadFigura() : void
+pertenece(p : Punto) : boolean
+setZoom(zoom : int) : void
161
Una aplicación de ejemplo – Diseño del prototipo
Para lograr una independencia entre la superficie de dibujo y el dibujado de
los objetos, creamos una clase llamada Dibujante, que es la encargada de
dibujar en una instancia de LienzoCuenca, de manera que Graficable, no
accede directamente al lienzo, sino que lo haga a través de Dibujante
Dibujante
-colorLinea : Color
-g : Graphics
-zoom : int
+drawCuadrado(cuad : CuadradoOra) : void
+drawElipse(e : ElipseOra) : void
+drawPolilinea(p : ArrPuntosOra) : void
+drawPolilinea(p : PolilineaOra) : void
+drawPolilineaDoble(p : ArrPuntosOra) : void
+drawPolilineaDoble(p : PolilineaOra) : void
+drawPolilineaGruesa(p : ArrPuntosOra) : void
+drawPolilineaGruesa(p : PolilineaOra) : void
+drawTriangulo(t : TrianguloOra) : void
+setColorLinea(c : Color) : void
+drawString(s : String, x : int, y : int, tam : int) : vo
Para cada objeto de la cuenca que es mostrado gráficamente fue creada una
clase para mostrar los atributos descriptivos del objeto.
JDialog
frmEmbalse
frmSalidaEmb
frmHoyaInter
frmFlujo
frmRegNat
FrmCapAguaPot
frmNodo
FrmCanal
FrmTramo
FrmCentralHidro
Las pantallas que representan estos diálogos, las podemos encontrar en
C.3.9 al C.3.16.
Como las clases generadas con JPUB, no pueden ser mostradas directamente
sobre el LienzoCuenca, creamos tres clases GuiEmbalse, GuiNodo, GuiFlujo,
como
subclases
de
EmbalseOraRef,
NodoOraRef,
FlujoOraRef
respectivamente; y las tres implementan la interfaz Graficable.
La clase
GuiFlujo encapsula a todos los flujos. El siguiente diagrama muestra dicha
relación:
162
Una aplicación de ejemplo – Diseño del prototipo
«Interface»
Graficable
NodoOraRef
EmbalseOraRef
FlujoOraRef
GuiEmbalse
GuiNodo
-codigo : String
-frm : frmNodo
-graf : ElipseOra
-zoom : int
+dibujar(d : Dibujante) : void
+dimensionMinima() : Dimension
+dlgAtributos() : void
+getZoom() : int
+loadFigura() : void
+pertenece(p : Punto) : boolean
+setZoom(zoom : int) : void
1
1
1
ElipseOra
1
frmNodo
GuiFlujo
-alerta : boolean
-frm : frmNodo
-graf : ElipseOra
-zoom : int
-alertaEmb() : boolean
+dibujar(d : Dibujante) : void
+dimensionMinima() : Dimension
+dlgAtributos() : void
+getZoom() : int
+loadFigura() : void
+pertenece(p : Punto) : boolean
+setZoom(zoom : int) : void
-alertaFlujo() : boolean
-colineales(a : Punto, b : Punto, c : Punto) : boolean
-dibujarCentHidro(d : Dibujante) : void
-dibujarFlujo(d : Dibujante) : void
-dimensionMinima(fl : PolilineaOra) : Dimension
-dimensionMinimaCh() : Dimension
-dimensionMinimaGFlujo() : Dimension
-pertenece(arr : ArrPuntosOra, p : Punto) : boolean
-pertenece(gch : GrafCentHidroOra, p : Punto) : boolean
-setZoomCentHidro(zoom : int) : void
-setZoomGrafFlujo(zoom : int) : void
1
1
GrafCuencaOra
-alerta : boolean
-codigo : String
-frm : frmNodo
-graf : ElipseOra
-zoom : int
-alertaEmb() : boolean
+dibujar(d : Dibujante) : void
+dimensionMinima() : Dimension
+dlgAtributos() : void
+getZoom() : int
+loadFigura() : void
+pertenece(p : Punto) : boolean
+setZoom(zoom : int) : void
1
1
1
ElipseOra
1
frmEmbalse
1
1
frmFlujo
Como puede observar, utilizamos las clases que referencian a un objeto y no
las que almacenan directamente el objeto. Esto se debe a que estas últimas,
almacenan una copia del objeto persistente, lo que dificulta la modificación
del objeto y la consistencia entre la vista del usuario y la base de datos. Por
el contrario, las referencias de objetos, permiten a las aplicaciones obtener y
modificar el objeto persistente referenciado en cualquier momento, a través
de los métodos setValue(C) (actualiza el objeto referenciado con C) y
getValue() (obtiene el objeto referenciado).
163
Una aplicación de ejemplo – Diseño del prototipo
La pantalla principal del prototipo es la clase frame1 cuyo código fuente
puede ser visto en C.4.2.1. El siguiente diagrama muestra la relación que
existe entre Frame1 y las demás clases.
JPanel
1
BDObjCuenca
1
Frame1
CuencaOraRef
1
1
1
1
FrmConeccion
1
1
LienzoCuenca
La clase Frame1, además de los atributos que son parte de la interfaz gráfica
estándar, cuenta con cuatro atributos, uno es del tipo CuencaOraRef, que
almacena una referencia a la cuenca que actualmente está siendo desplegada.
Otro es del tipo FrmConexion, que permite desplegar la ventana de conexión
y almacenar los datos necesarios para realizarla. Otro es del tipo
LienzoCuenca que almacena y muestra los objetos de la cuenca. Y por
último, un atributo del tipo BDObjCuenca. La clase BDObjCuenca es una
especialización de la clase ConectorJdbc que encapsula la conexión entre
java y la base de datos, almacenando los datos básicos para la conexión.
Estos son: el nombre del usuario (atributo usr), la contraseña (passwd), el
driver a utilizar para la conexión (driver) y la URL JDBC que indica la dirección
de la base de datos (url). El Atributo Connection, almacena la conexión entre
java y la base de datos.
Los métodos de la clase ConectorJdbc permiten
abrir y cerrar una conexión, consultar el estado de la conexión (abierta o
cerrada), obtener y modificar el estado de los atributos (set y get). La clase
BDObjCuenca, no incorpora nuevos atributos, pero sí nuevos métodos que
permiten obtener los objetos de una cuenca, ingresar cuencas, ríos y flujos a
la base de datos, eliminar ríos y cuencas. El siguiente diagrama, muestra
dicha jerarquía:
164
Una aplicación de ejemplo – Diseño del prototipo
ConectorJdbc
connection : OracleConnection
driver : String
passwd : String
url : String
usr : String
+close() : void
+getConnection() : Connection
+getDriver() : String
+getOracleConnection() : OracleConnection
+getPasswd() : String
+getUrl() : String
+getUsr() : String
+isClosed() : boolean
+isOpen() : boolean
+open(url : String, driverName : String, user : String, passwd : String) : void
+setDriver(driver : String) : void
+setPasswd(passwd : String) : void
+setUrl(url : String) : void
+setUsr(usr : String) : void
BDObjCuenca
+eliminar(c : CuencaOra) : void
+eliminar(c : RioOra) : void
+getAllEmbalseoraRef(c : CuencaOra) : Vector
+getAllFigRef(c : CuencaOra) : Vector
+getAllFlujosOraRef(c : CuencaOra) : Vector
+getAllNodoOraRef(c : CuencaOra) : Vector
+getCuenca(codigo : String) : CuencaOra
+getCuencaRef(codigo : String) : CuencaOraRe
+getRioRef(codigo : String) : RioOraRef
+Insertar(c : CuencaOra) : void
+insertar(flujo : FlujoOra) : GuiFlujo
+Insertar(c : RioOra) : void
La siguiente pantalla corresponde a Frame1, en ella podemos apreciar el
comportamiento final de las clases Frame1, LienzoCuenca, GuiNodo,
GuiFlujo y GuiEmbalse.
165
Una aplicación de ejemplo – Diseño del prototipo
La parte blanca, donde se dibujan los objetos de la cuenca, corresponde a
una instancia de la clase LienzoCuenca.
Las flechas corresponden a
instancias de la clase GuiFlujo, los óvalos a GuiNodo y los triángulos a
GuiEmbalse. La misma imagen, pero de un tamaño más grande, puede ser
vista en C.3.3
Las
ventanas
(C.3.2),
restantes:
Frame1_AboutBox
FrmCuenca
(ver
C.3.4),
(C.3.17),
FrmAbrirCuenca
FrmModificarRio
(C.3.7),
FrmResultConsulta (C.3.6), FrmSimular (ver C.3.5), FrmZoom (ver C.3.5),
son llamadas desde Frame1, dependiendo de la opción del menú utilizada
por el usuario.
Para conocer las opciones del menú disponible vea las
pantallas desde C.3.18 a la C.3.23
6.3.2 Diagramas de colaboración
6.3.2.1 Simulación
El método que realiza la simulación corresponde a Simular() del tipo definido
en Oracle Cuenca. Este método es ejecutado en el servidor, y es invocado
desde la aplicación java a partir de un objeto del tipo CuencaOra. Antes de
mostrar el diagrama de colaboración para este método, veremos el contexto
en el que es invocado.
Cuando el usuario escoge la opción del menú cuenca (D.3.18) “Iniciar
simulación...” de la clase Frame1. Esta opción abre la ventana de simulación
(FRMSimular), pasándole como parámetro una referencia de Frame1 y otra
al atributo dataBase de Frame1 que almacena la conexión abierta entre el
programa
y la
automáticamente,
base
es
de
datos.
invocado
Al abrir la ventana
FRMSimular,
por
su
el
sistema
método
this_windowOpened(...), que a su vez invoca al método iniciarSim() de la
clase FRMSimular. El método inicairSim() obtiene la cuenca mostrada por
Frame1 y la almacena en una instancia
llamada cuenca que es del tipo
CuencaOra. Luego invoca al método Simular() sobre Cuenca, el cual realiza
166
Una aplicación de ejemplo – Diseño del prototipo
la simulación.
Finalizado el método Simular(), es invocado el método
reloadFiguras() de la instancia lienzo, (que es un atributo de Frame1 del
tipo LienzoCuenca) para actualizar los objetos mostrados.
El siguiente Diagrama de colaboración muestra la ejecución del método
Simular(), el cual es ejecutado en la base de datos.
La iteración es de 1..6 porque son 6 mesde de simulación.
En cada mes, invocaremos el método distribuirCaudal(i)
sobre todos los nodos de la cuenca
Simular()
Conjunto de nodos que
pertenecen a la cuenca
ordenados.
1*:[i:=1..6]
[para cada] no:=siguiente( )
:Cuenca
«cursor Sql»
:Nodo
2.4a: [existe embalse] entrada(Ent, i )
:Embalse
2: distribuirCaudal(i)
2.4b*: [no existe embalse] fs:=siguiente()
2.3: setCaudal(Ent, i )
no:Nodo
2.6b*: [no existe embalse] fs:=siguiente()
2.5b: [no existe embalse]
dem:=dem+Demanda(Ent, i )
:arr_caudal
«cursor Sql»
:Flujo
f:Flujo
2.7b: [no existe embalse]
entrada(prop, i)
prop, contiene
el caudal proporcional
a la demanda del flujo
Atributo del
nodo no
2.2: Ent=Ent+Salida( i )
2.1*: [para cada] f:=siguiente( )
f:Flujo
«cursor
Sql»
no:Nodo
:Flujo
conjunto de flujos que
aportan caudales a un nodo
El método simular() de la cuenca, invoca al método distribuirCaudal(...),
sobre cada uno de sus nodos, para cada mes de la simulación.
Para la
distribución de caudales, el nodo calcula el total de caudal de entrada a partir
de los flujos que le aportan caudal. Para ello, invoca al método salida(...)
167
Una aplicación de ejemplo – Diseño del prototipo
sobre ellos.
Luego, almacena dicho caudal en su arreglo de caudales,
invocando el método SetCaudal(...) sobre el atributo caudales. Si el nodo
tiene un embalse, todo el caudal de entrada es aportado a él, para ello invoca
al método del embalse entrada(...).
Si no hay un embalse en el nodo,
entonces, se distribuye el caudal de entrada, proporcional a la demanda de
los flujos que extraen caudal del nodo. Para calcular la demanda total, invoca
el método demanda(...) sobre todos los flujos que le extraen caudal, y
acumula su resultado. Luego, es asignado el caudal que le corresponde a
cada uno de los flujos con el método entrada(...).
6.3.3 Limitaciones Encontradas
6.3.3.1 Limitaciones de PL/SQL
•
No podemos navegar a través de los atributos del tipo REF de un tipo.
•
No podemos actualizar un atributo de un objeto persistente
directamente, tenemos que utilizar UPDATE
•
No podemos modificar un atributo en funciones.
•
Sólo podemos invocar métodos del tipo procedimiento en objetos
transitorios. No podemos utilizar esta clase de métodos dentro de
predicados SELECT, UPDATE, O DELETE.
6.3.3.2 Limitaciones de Oracle y la exportación de tipos
•
Cuando exporto un tipo a java con JPUB, todos los métodos son
ejecutados por el servidor.
168
7 Conclusiones
A pesar de las limitaciones del estándar para el manejo de objetos, este
obtiene una buena calificación en nuestra evaluación, un 78,25%. Lo que nos
permite concluir que, en la próxima versión del estándar (SQL:200n), estará
cubriendo prácticamente el 100% de las características que debe tener una
base de datos orientada a objeto.
Por otro lado, Oracle 8i obtiene una
calificación de 70,58%, más baja que el estándar, esto se debe principalmente
a la falta de herencia, un encapsulamiento incompleto, y el deficiente soporte
a la evolución de esquemas.
El estándar, con sus capacidades y limitaciones, es lo suficientemente
robusto para permitir que los desarrolladores lo utilicen para hacer persistir
sus objetos, puesto que las limitaciones son pocas y en áreas no
fundamentales.
Pero Oracle 8i, por su falta de herencia, hace que el
desarrollo de aplicaciones orientadas a objeto en él sea muy complejo y poco
productivo. Es de esperar que en uno o dos años más ya existan productos
que implementen todas las instrucciones del estándar SQL:1999.
Uno de los beneficios de la tecnología de objetos incluida en el estándar
SQL:1999 y en Oracle 8i es permitir que
los usuarios incrementen el
conjunto de tipos de datos provisto por el sistema.
Esto permite la
reutilización del código, lo que disminuye el tiempo de desarrollo y la
complejidad.
Además, trae como consecuencia una mayor eficiencia a la
hora de mantener sistemas, porque bastaría con modificar un tipo (ALTER
TYPE) para que automáticamente se modifiquen todas las tablas y tipos que
dependen de él. Lamentablemente dicha actualización no está presente en
Oracle 8i aunque cuenta con el predicado ALTER TYPE, este sólo permite
agregar nuevos métodos, lo cual es muy limitado. En SQL:1999 esto sí es
posible, pero tiene algunas restricciones.
La herencia y el polimorfismo, también traen beneficios a las bases de datos,
puesto que permiten extender el sistema fácilmente para que se adapte a los
cambios de requerimientos.
Permitiendo así un desarrollo incremental, lo
que disminuye la complejidad del desarrollo.
Estas características están
presentes en SQL:1999, pero no en Oracle 8i.
170
Conclusiones
Otra de las capacidades de SQL:1999 y de Oracle 8i, son las vistas de objetos.
Estas permiten definir una capa de orientación a objeto sobre datos
relacionales, lo que elimina la necesidad de migrar las tablas relacionales a
tablas de objetos.
El contar con el estándar SQL:1999 garantiza a las aplicaciones una
compatibilidad, portabilidad e independencia entre las distintas bases de
datos que implementan el estándar
Una limitación del estándar SQL:1999 y Oracle 8i es que carece de la
funcionalidad para manejar versiones y configuraciones de objetos. Esta es la
desventaja más grande entre las bases de datos objeto-relacional y las bases
de datos orientadas a objeto puras.
Gracias a la implementación del prototipo del capítulo 6, podemos deducir
que la interacción que logramos entre Oracle y Java es bastante transparente,
gracias a la utilidad JPUB, que permite generar las clases Java a partir de los
tipos definidos en Oracle.
El presente trabajo puede ser complementado con una investigación similar a
ésta pero sobre el estándar ODMG-93 y algunas bases de datos orientadas a
objeto puras que lo implementen. Y a partir ello realizar una comparación
entre los estándares y los productos para determinar cuál de los dos resuelve
mejor el problema de la persistencia.
Otro trabajo interesante sería, realizar la misma descripción y análisis hecho
para Oracle 8i, sobre una o más bases de datos objeto relacional, como
puede ser Informix o DB2 DE IBM, y luego realizar una comparación entre
ellas.
171
Apéndice A: Sintaxis de
SQL:1999 Relacionada con la
OO.
A.1 Leyenda
Para la descripción del lenguaje se utiliza una sintaxis extendida de la
gramática BNF (Backus Normal Form o Forma normal de Backus) [25].
En la gramática BNF, cada elemento sintáctico es conocido como un símbolo
no terminal, el cual es definido por el significado de una regla de
producción [25].
Esto define el elemento en términos de una fórmula
consistente de: caracteres, cadenas de caracteres, y elementos sintácticos
que pueden ser usados para formar una instancia del [25].
La simbología es la siguiente:
Símbolo Significado
< >
Las palabras encerradas en estos símbolos, representa un
símbolo no terminal.
El operador de definición es utilizado en una regla de
::=
producción para separar el elemento definido por la regla y su
definición. A la izquierda del operador, aparece el símbolo no
terminal, y a la derecha, la fórmula que lo define.
[ ]
Los corchetes indican que el elemento en una fórmula es
{ }
Las llaves agrupan elementos en una fórmula.
|
Indica que la porción de la fórmula que aparece después de la
...
Indica que el elemento
opcional.
barra es una alternativa a la porción que precede a la barra.
que aparece antes de los puntos
suspensivos, puede ser repetido n veces
La sintaxis expuesta en este apéndice es tan sólo un extracto del estándar,
por ser éste de gran tamaño (1.196 páginas).
A.2 Sentencias
A.2.1 Creación de tipos (CREATE TYPE)
Especifica un tipo de datos definido por el usuario.
Formato:
<user-defined type definition> ::=
CREATE TYPE <user-defined type body>
<user-defined type body> ::=
<user-defined type name>
[ <subtype clause> ]
[ AS <representation> ]
[ <instantiable clause> ]
<finality>
[ <reference type specification> ]
[ <cast option> ]
[ <method specification list> ]
<subtype clause> ::= UNDER <supertype name>
<supertype name> ::= <user-defined type>
<representation> ::= <predefined type>| <member list>
<member list> ::=
<left paren> <member> [ { <comma> <member> }... ]
<right paren>
<member> ::= <attribute definition>
<instantiable clause> ::= INSTANTIABLE | NOT INSTANTIABLE
<finality> ::= FINAL | NOT FINAL
<reference type specification> ::=
<user-defined representation>
| <derived representation>
| <system-generated representation>
<user-defined representation> ::=
REF USING <predefined type> [ <ref cast option> ]
<derived representation> ::= REF FROM <list of attributes>
<system-generated representation> ::=
REF IS SYSTEM GENERATED
<ref cast option> ::=
[ <cast to ref> ]
[ <cast to type> ]
<cast to ref> ::=
CAST <left paren> SOURCE AS REF <right paren>
WITH <cast to ref identifier>
Apéndice A – Sintaxis SQL:1999
<cast to ref identifier> ::= <identifier>
<cast to type> ::=
CAST <left paren> REF AS SOURCE <right paren>
WITH <cast to type identifier>
<cast to type identifier> ::=<identifier>
<list of attributes> ::=
<left paren> <attribute name> [ { <comma>
<attribute name> }...] <right paren>
<cast option> ::=
[ <cast to distinct> ]
[ <cast to source> ]
<cast to distinct> ::=
CAST <left paren> SOURCE AS DISTINCT <right paren>
WITH <cast to distinct identifier>
<cast to distinct identifier> ::= <identifier>
<cast to source> ::=
CAST <left paren> DISTINCT AS SOURCE <right paren>
WITH <cast to source identifier>
<cast to source identifier> ::= <identifier>
<method specification list> ::=
<method specification> [ { <comma>
<method specification> }... ]
<method specification> ::=
<original method specification>
| <overriding method specification>
<original method specification> ::=
<partial method specification>
[ SELF AS RESULT ]
[ SELF AS LOCATOR ]
[ <method characteristics> ]
<overriding method specification> ::=
OVERRIDING <partial method specification>
<partial method specification> ::=
[ INSTANCE | STATIC ] METHOD <method name> <SQL
parameter declaration list>
<returns clause>
[ SPECIFIC <specific name> ]
<method characteristics> ::= <method characteristic>...
<method characteristic> ::=
<language clause>
| <parameter style clause>
| <deterministic characteristic>
| <SQL-data access indication>
| <null-call clause>
| <transform group specification>
175
Apéndice A – Sintaxis SQL:1999
<language clause> ::= LANGUAGE <language name>
<language name> ::=
ADA |C |COBOL | FORTRAN | MUMPS | PASCAL | PLI | SQL
A.2.2 Definición de atributos
Define los atributos de un tipo estructurado
Formato:
<attribute definition> ::=
<attribute name> <data type>
[ <reference scope check> ]
[ <attribute default> ]
[ <collate clause> ]
<attribute default> ::= <default clause>
<default clause> ::= DEFAULT <default option>
<default option> ::=
<literal>
| <datetime value function>
| USER
| CURRENT_USER
| CURRENT_ROLE
| SESSION_USER
| SYSTEM_USER
| CURRENT_PATH
| <implicitly typed value specification>
A.2.3 Modificación de tipos (ALTER TYPE)
Permite agregar y eliminar atributos o métodos.
Formato:
<alter type statement> ::=
ALTER TYPE <path-resolved user-defined type name>
<alter type action>
<alter type action> ::=
<add attribute definition>
| <drop attribute definition>
| <add original method specification>
| <add overriding method specification>
| <drop method specification>
<add attribute definition> ::=
ADD ATTRIBUTE <attribute definition>
<drop attribute definition> ::=
DROP ATTRIBUTE <attribute name> RESTRICT
<add original method specification> ::=
ADD <original method specification>
<add overriding method specification> ::=
176
Apéndice A – Sintaxis SQL:1999
ADD <overriding method specification>
<drop method specification> ::=
DROP <specific routine designator> RESTRICT
<drop data type statement> ::=
DROP TYPE <path-resolved user-defined type name>
<drop behaviour>
<drop behaviour> ::= CASCADE | RESTRICT
<specific routine designator> ::=
SPECIFIC <routine type> <specific name>
| <routine type> <member name>
[ FOR <path-resolved user-defined type name> ]
<routine type> ::=
ROUTINE
| FUNCTION
| PROCEDURE
| [ INSTANCE | STATIC ] METHOD
<member name> ::=
<schema qualified routine name> [ <data type list> ]
<data type list> ::=
<left paren> [ <data type> [ { <comma> <data type> }... ] ]
<rige paren>
A.2.4 Creación de métodos, funciones y procedimientos
Permite definir métodos, funciones y procedimientos almacenados.
Formato:
<SQL-invoked routine> ::= <schema routine>
<schema routine> ::= <schema procedure> | <schema function>
<schema procedure> ::= CREATE <SQL-invoked procedure>
<schema function> ::= CREATE <SQL-invoked function>
<SQL-invoked procedure> ::=
PROCEDURE <schema qualified routine name>
<SQL parameter declaration list>
<routine characteristics>
<routine body>
<SQL-invoked function> ::=
{ <function specification> | <method specification
designator> }
<routine body>
<SQL parameter declaration list> ::=
<left paren>
[ <SQL parameter declaration> [ { <comma> <SQL
parameter declaration> }... ] ]
<right paren>
<SQL parameter declaration> ::=
[ <parameter mode> ] [ <SQL parameter name> ]
<parameter type>
177
Apéndice A – Sintaxis SQL:1999
[ RESULT ]
<parameter mode> ::= IN | OUT | INOUT
<parameter type> ::= <data type> [ <locator indication> ]
<locator indication> ::= AS LOCATOR
<function specification> ::=
FUNCTION <schema qualified routine name>
<SQL parameter declaration list>
<returns clause>
<routine characteristics>
[ <dispatch clause> ]
<method specification designator> ::=
[ INSTANCE | STATIC ] METHOD <method name> <SQL
parameter declaration list>
[ <returns clause> ]
FOR <path-resolved user-defined type name>
<routine characteristics> ::=[ <routine characteristic>... ]
<routine characteristic> ::=
<language clause>
| <parameter style clause>
| SPECIFIC <specific name>
| <deterministic characteristic>
| <SQL-data access indication>
| <null-call clause>
| <transform group specification>
| <dynamic result sets characteristic>
<dynamic result sets characteristic> ::=
DYNAMIC RESULT SETS <maximum dynamic result sets>
<parameter style clause> ::=
PARAMETER STYLE <parameter style>
<dispatch clause> ::= STATIC DISPATCH
<returns clause> ::=
RETURNS <returns data type> [ <result cast> ]
<result cast> ::= CAST FROM <result cast from type>
<result cast from type> ::=
<data type> [ <locator indication> ]
<returns data type> ::= <data type> [ <locator indication> ]
<routine body> ::=
<SQL routine body>| <external body reference>
<SQL routine body> ::= <SQL procedure statement>
<external body reference> ::=
EXTERNAL [ NAME <external routine name> ]
[ <parameter style clause> ]
[ <external security clause> ]
<external security clause> ::=
EXTERNAL SECURITY DEFINER
| EXTERNAL SECURITY INVOKER
178
Apéndice A – Sintaxis SQL:1999
| EXTERNAL SECURITY IMPLEMENTATION DEFINED
<parameter style> ::= SQL | GENERAL
<deterministic characteristic> ::=
DETERMINISTIC | NOT DETERMINISTIC
<SQL-data access indication> ::=
NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA
<null-call clause> ::=
RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT
<maximum dynamic result sets> ::= <unsigned integer>
<transform group specification> ::=
TRANSFORM GROUP
{ <single group specification> | <multiple group
specification> }
<single group specification> ::= <group name>
<multiple group specification> ::=
<group specification>
[ { <comma> <group specification> }... ]
<group specification> ::=
<group name> FOR TYPE <path-resolved user-defined type name>
A.2.5 Modificación de métodos, funciones y procedimientos
Permite modificar la definición de una función, procedimiento o de un
método.
Formato:
<alter routine statement> ::=
ALTER <specific routine designator>
<alter routine characteristics>
<alter routine behaviour>
<alter routine characteristics> ::=
<alter routine characteristic>...
<alter routine characteristic> ::=
<language clause>
| <parameter style clause>
| <SQL-data access indication>
| <null-call clause>
| <dynamic result sets characteristic>
| NAME <external routine name>
<alter routine behaviour> ::= RESTRICT
<drop routine statement> ::=
DROP <specific routine designator> <drop behaviour>
<specific routine designator> ::=
SPECIFIC <routine type> <specific name>
| <routine type> <member name>
[ FOR <path-resolved user-defined type name> ]
179
Apéndice A – Sintaxis SQL:1999
<routine type> ::=
ROUTINE
| FUNCTION
| PROCEDURE
| [ INSTANCE | STATIC ] METHOD
<member name> ::=
<schema qualified routine name> [ <data type list> ]
<data type list> ::=
<left paren> [ <data type> [ { <comma> <data type> }... ] ]
<rige paren>
A.2.6 CAST definido por el usuario
Permite crear un CAST definido por el usuario
Formato:
<user-defined cast definition> ::=
CREATE CAST <left paren> <source data type>
AS <target data type> <right paren>
WITH <cast function>
[ AS ASSIGNMENT ]
<cast function> ::= <specific routine designator>
<source data type> ::= <data type>
<target data type> ::= <data type>
<specific routine designator> ::=
SPECIFIC <routine type> <specific name>
| <routine type> <member name>
[ FOR <path-resolved user-defined type name> ]
<routine type> ::=
ROUTINE
| FUNCTION
| PROCEDURE
| [ INSTANCE | STATIC ] METHOD
<member name> ::=
<schema qualified routine name> [ <data type list> ]
<data type list> ::=
<left paren> [ <data type> [ { <comma> <data type> }... ] ]
<rige paren>
180
Apéndice A – Sintaxis SQL:1999
A.2.7 Eliminación de un CAST
Permite eliminar un CAST definido por el usuario
Formato:
<drop user-defined cast statement> ::=
DROP CAST <left paren> <source data type> AS
<target data type> <right paren> <drop behaviour>
A.2.8 Definición del ORDERING de un tipo.
Define la forma en que el sistema debe comparar dos instancias de un mismo
tipo.
Formato:
<user-defined ordering definition> ::=
CREATE ORDERING FOR
<path-resolved user-defined type name> <ordering form>
<ordering form> ::=
<equals ordering form> | <full ordering form>
<equals ordering form> ::=EQUALS ONLY BY <ordering category>
<full ordering form> ::=ORDER FULL BY <ordering category>
<ordering category> ::=
<relative category>
| <map category>
| <state category>
<relative category> ::=
RELATIVE WITH <relative function specification>
<map category> ::=
MAP WITH <map function specification>
<state category> ::= STATE [ <specific name> ]
<relative function specification> ::=
<specific routine designator>
<map function specification> ::=
<specific routine designator>
<specific routine designator> ::=
SPECIFIC <routine type> <specific name>
| <routine type> <member name>
[ FOR <path-resolved user-defined type name> ]
<routine type> ::=
ROUTINE
| FUNCTION
| PROCEDURE
181
Apéndice A – Sintaxis SQL:1999
| [ INSTANCE | STATIC ] METHOD
<member name> ::=
<schema qualified routine name> [ <data type list> ]
<data type list> ::=
<left paren> [ <data type> [ { <comma> <data type> }... ] ]
<rige paren>
A.2.9 Eliminación de un user definer ordering
Permite eliminar la definición de un user definer ordering.
Formato:
<drop user-defined ordering statement> ::=
DROP ORDERING FOR
<path-resolvedEuser-defined type name> <drop behaviour>
A.2.10 Funciones de transformación de tipos
Permite definir una o más funciones de transformación para tipos definidos
por el usuario.
Formato:
<transform definition> ::=
CREATE { TRANSFORM | TRANSFORMS } FOR
<path-resolved user-defined type name>
<transform group>...
<transform group> ::=
<group name> <left paren> <transform element list>
<right paren>
<group name> ::= <identifier>
<transform element list> ::=
<transform element> [ <comma> <transform element> ]
<transform element> ::= <to sql> | <from sql>
<to sql> ::= TO SQL WITH <to sql function>
<from sql> ::= FROM SQL WITH <from sql function>
<to sql function> ::= <speciic routine designator>
<from sql function> ::= <specific routine designator>
<specific routine designator> ::=
SPECIFIC <routine type> <specific name>
| <routine type> <member name>
[ FOR <path-resolved user-defined type name> ]
<routine type> ::=
ROUTINE
| FUNCTION
182
Apéndice A – Sintaxis SQL:1999
| PROCEDURE
| [ INSTANCE | STATIC ] METHOD
<member name> ::=
<schema qualified routine name> [ <data type list> ]
<data type list> ::=
<left paren> [ <data type> [ { <comma> <data type> }... ] ]
<rige paren>
A.2.11 Eliminación de funciones de transformación
Permite eliminar funciones de transformación de tipos definidos por el
usuario.
Formato:
<drop transform statement> ::=
DROP { TRANSFORM | TRANSFORMS }
<transforms to be dropped>
FOR <path-resolved user-defined type name>
<drop behaviour>
<transforms to be dropped> ::=
ALL | <transform group element>
<transform group element> ::= <group name>
A.2.12 Definición de Tablas (CREATE TABLE)
Permite definir tablas, tanto relacionales como typed tables, subtablas, y
supertablas.
Formato:
<table definition> ::=
CREATE [ <table scope> ] TABLE <table name>
<table contents source>
[ ON COMMIT <table commit action> ROWS ]
<table contents source> ::=
<table element list>
| OF <user-defined type>
[ <subtable clause> ]
[ <table element list> ]
<table scope> ::= <global or local> TEMPORARY
<global or local> ::= GLOBAL | LOCAL
<table commit action> ::= PRESERVE | DELETE
<table element list> ::=
<left paren> <table element> [ { <comma> <table
element> }... ] <right paren>
183
Apéndice A – Sintaxis SQL:1999
<table element> ::=
<column definition>
| <table constraint definition>
| <like clause>
| <self-referencing column specification>
| <column options>
<self-referencing column specification> ::=
REF IS <self-referencing column name> <reference
generation>
<reference generation> ::=
SYSTEM GENERATED | USER GENERATED | DERIVED
<self-referencing column name> ::= <column name>
<column options> ::=
<column name> WITH OPTIONS <column option list>
<column
[
[
[
[
option list> ::=
<scope clause> ]
<default clause> ]
<column constraint definition>... ]
<collate clause> ]
<subtable clause> ::= UNDER <supertable clause>
<supertable clause> ::= <supertable name>
<supertable name> ::= <table name>
<like clause> ::= LIKE <table name>
<column definition> ::=
<column name>
{ <data type> | <domain name> }
[ <reference scope check> ]
[ { <default clause> | <identity column specification>
} ]
[ <column constraint definition>... ]
[ <collate clause> ]
<column constraint definition> ::=
[ <constraint name definition> ]
<column constraint> [ <constraint characteristics> ]
<column constraint> ::=
NOT NULL
| <unique specification>
| <references specification>
| <check constraint definition>
<reference scope check> ::=
REFERENCES ARE [ NOT ] CHECKED
[ ON DELETE <reference scope check action> ]
<reference scope check action> ::=
<referential action>
<identity column specification> ::=
184
Apéndice A – Sintaxis SQL:1999
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ <start
and increment> ]
<start and increment> ::=
<left paren> <start or increment 1> [ <comma> <start or
increment 2> ] <right paren>
<start or increment 1> ::= <start or increment>
<start or increment 2> ::= <start or increment>
<start or increment>::=
<start specification> | <increment specification>
<start specification> ::= START WITH <start value>
<increment specification> ::= INCREMENT BY <increment>
<start value> ::= <signed numeric literal>
<increment> ::= <signed numeric literal>
<table constraint definition> ::=
[ <constraint name definition> ]
<table constraint> [ <constraint characteristics> ]
<table constraint> ::=
<unique constraint definition>
| <referential constraint definition>
| <check constraint definition>
<unique constraint definition> ::=
<unique specification> <left paren> <unique column
list> <right paren>
| UNIQUE ( VALUE )
<unique specification> ::= UNIQUE | PRIMARY KEY
<unique column list> ::= <column name list>
<referential constraint definition> ::=
FOREIGN KEY <left paren> <referencing columns> <right
paren> <references specification>
<references specification> ::=
REFERENCES <referenced table and columns>
[ MATCH <match type> ]
[ <referential triggered action> ]
<match type> ::= FULL | PARTIAL | SIMPLE
<referencing columns> ::= <reference column list>
<referenced table and columns> ::=
<table name> [ <left paren> <reference column list>
<right paren> ]
185
Apéndice A – Sintaxis SQL:1999
<reference column list> ::= <column name list>
<referential triggered action> ::=
<update rule> [ <delete rule> ]
| <delete rule> [ <update rule> ]
<update rule> ::= ON UPDATE <referential action>
<delete rule> ::= ON DELETE <referential action>
<referential action> ::=
CASCADE | SET NULL
| SET DEFAULT | RESTRICT
| NO ACTION
<check constraint definition> ::=
CHECK <left paren> <search condition> <right paren>
A.2.13 Modificación de tablas (ALTER TABLE)
Permite cambiar la definición de una tablas.
Formato:
<alter table statement> ::=
ALTER TABLE <table name> <alter table action>
<alter table action> ::=
<add column definition>
| <alter column definition>
| <drop column definition>
| <add table constraint definition>
| <drop table constraint definition>
<add column definition> ::=
ADD [ COLUMN ] <column definition>
<alter column definition> ::=
ALTER [ COLUMN ] <column name> <alter column action>
<alter column action> ::=
<set column default clause>
| <drop column default clause>
| <add column scope clause>
| <drop column scope clause>
<set column default clause> ::=
SET <default clause>
<drop column default clause> ::=
DROP DEFAULT
<add column scope clause> ::=
ADD <scope clause>
186
Apéndice A – Sintaxis SQL:1999
<drop column scope clause> ::=
DROP SCOPE <drop behaviour>
<drop column definition> ::=
DROP [ COLUMN ] <column name> <drop behaviour>
<add table constraint definition> ::=
ADD <table constraint definition>
<drop table constraint definition> ::=
DROP CONSTRAINT <constraint name> <drop behaviour>
A.2.14 Eliminación de tablas (DROP TABLE)
Permite eliminar una tabla.
Formato:
<drop table statement> ::=
DROP TABLE <table name> <drop behaviour>
A.2.15 Inserción de filas (INSERT INTO)
Permite insertar una fila en una tabla.
Formato:
<insert statement> ::=
INSERT INTO <insertion target>
<insert columns and source>
<insertion target> ::=<table name>
<insert columns and source> ::=
<from subquery>
| <from constructor>
| <from default>
<from subquery> ::=
[ <left paren> <insert column list> <right paren> ]
[ override clause> ]
<query expression>
<from constructor> ::=
[ <left paren> <insert column list> <right paren> ]
[ <override clause> ]
<contextually typed table value constructor>
<override clause> ::=
OVERRIDING USER VALUE
| OVERRIDING SYSTEM VALUE
<from default> ::=
DEFAULT VALUES
<insert column list> ::= <column name list>
187
Apéndice A – Sintaxis SQL:1999
<contextually typed table value constructor> ::=
VALUES <contextually typed row value expression list>
<contextually typed row value expression list> ::=
<contextually typed row value expression>
[ { <comma> <contextually typed row value expression> }... ]
<contextually typed row value expression> ::=
<row value special case>
| <contextually typed row value constructor>
<row value special case> ::=
<value specification>
| <value expression>
A.2.16 Actualización de filas (UPDATE)
Permite modificar el contenido de una fila existente.
Formato:
<update statement: searched> ::=
UPDATE <target table>
SET <set clause list>
[ WHERE <search condition> ]
<set clause list> ::=
<set clause> [ { <comma> <set clause> }... ]
<set clause> ::=
<update target> <equals operator> <update source>
| <mutated set clause> <equals operator> <update source>
<update target> ::=
<object column>
| <object column>
<left bracket or trigraph> <simple value specification>
<right bracket or trigraph>
<object column> ::= <column name>
<mutated set clause> ::= <mutated target> <period> <method name>
<mutated target> ::=
<object column>
| <mutated set clause>
<update source> ::=
<value expression>
| <contextually typed value specification>
A.2.17 Eliminación de filas (DELETE FROM)
Permite modificar el contenido de una fila existente.
Formato:
188
Apéndice A – Sintaxis SQL:1999
<delete statement: searched> ::=
DELETE FROM <target table>
[ WHERE <search condition> ]
<target table> ::=
<table name>
| ONLY <left paren> <table name> <right paren>
189
Apéndice B: UML
B.1 ¿Qué es UML?
UML cuya sigla significa Unified Modeling Language (Lenguaje Unificado de
Modelado) fue desarrollado por Grady Booch, Jim Rumbaugh e Ivar Jacobson
en respuesta a una serie de necesidades [6]. UML es un lenguaje que permite
especificar, visualizar, construir y documentar artefactos de sistemas de
software, como también, modelar negocios y otros sistemas no software [6].
El UML representa una colección de las mejores prácticas de ingeniería que
han demostrado ser exitosas en el modelamiento de sistemas grandes y
complejos [37].
Como se manifiesta en el documento UML Sumary [37], los objetivos
principales que se perseguían al diseñar UML fueron:
“Proporcionar a los usuarios un lenguaje de modelización visual listo
para ser utilizado que sirviera para desarrollar e intercambiar
modelos con significado.
Proporcionar mecanismos de extensibilidad y especialización para
extender los conceptos esenciales.
Ser independiente de cualquier lenguaje de programación y de
cualquier proceso de desarrollo.
Proporcionar una base formal para comprender el lenguaje de
modelización.
Fomentar el crecimiento del mercado de las herramientas orientadas
a objeto
Dar soporte a conceptos de nivel superior, tales como, colaboración,
marcos de trabajo, patrones y componentes.
Integrar las mejores prácticas”
En UML existen diversos diagramas, estos son [6]:
Diagrama de clases. En este diagrama se definen las clases y cómo
se relacionan entre sí.
Diagrama de Objetos.
conjunto de objetos.
Es un diagrama de clases para sólo un
Apéndice C: UML
Diagrama de casos de uso. Un caso de uso muestra la interacción
entre distintos actores (por ejemplo clientes, empleado) y casos de
uso.
Diagrama de secuencias.
Un diagrama de secuencia muestra una
interacción de los objetos dispuestos en una secuencia temporal.
Diagrama de colaboración.
Un diagrama de colaboración muestra
los objetos y mensajes que se han pasado entre dichos objetos para
llevar a cabo alguna función.
Diagramas de estados.
Los diagramas de estado son diagramas
estándares de transición de estados. Muestran en qué estado puede
encontrarse un objeto y qué puede hacer que dicho objeto cambie de
estado.
Diagrama de actividad.
Un diagrama de actividad es un tipo de
diagrama de flujo. Representa puntos de operación y de decisión.
Diagrama de realización.
Un diagrama de realización muestra los
componentes del sistema y la forma en que interactúan entre sí. El
diagrama de realización puede mostrar los componentes software o
hardware del sistema.
Estos diagramas se suelen agrupar en vistas y las vistas se agrupan en tres
áreas [39]:
•
Clasificación estructural. Describe los elementos del sistema
y
sus
relaciones,
proporcionando
la
base
para
el
comportamiento dinámico.
•
Comportamiento dinámico. describe el comportamiento de
un sistema en el tiempo.
•
Gestión del modelo.
Describe la organización del propio
modelo en unidades jerárquicas denominadas paquetes.
Existen varias construcciones previas que permiten extender la capacidad de
UML pero de forma limitada. Estas construcciones son transversales a todas
las vistas.
La siguiente tabla [39] describe la agrupación antes descrita.
192
Apéndice C: UML
Área
Vista
Diagrama
estructural
vista estática
diagrama de clases
vista de casos de uso
diagrama de casos de uso
vista de implementación diagrama de componentes
vista de despliegue
Dinámica
diagrama de despliegue
Vista de máquinas de diagrama de estados
estados
Vista de actividad
Diagrama de actividad
Vista de interacción
Diagrama de secuencia
Diagrama de colaboración
Gestión del modelo
Vistas de gestión del Diagrama de clases
modelo
Extensión del modelo Todas
Todos
En la siguiente sección presentaremos la notación para los diagramas
utilizados para diseñar el prototipo.
B.1.1 Diagramas de clases
Los diagramas de clases son la base de los demás diagramas de UML. Ellos
describen la relación que existe entre las distintas clases, siendo las
principales: herencia, agregación, composición y asociación.
La notación
para una clase es un rectángulo con tres compartimentos
separados con líneas verticales, el superior para el nombre, el central para los
atributos y el inferior para sus métodos (ver figura 8):
figura 8: Ejemplo de clase [27]
193
Apéndice C: UML
Para indicar la visibilidad de un atributo o método, anteponemos uno de
estos caracteres: + (público), - (privado), # (protegido). Además, Si el
atributo o el método es estático, se subraya.
Es posible ocultar uno o más compartimientos (preservando el del nombre),
para facilitar la comprensión del diagrama.
También, podemos ocultar
aquellos métodos y atributos que forman parte de la implementación y no del
dominio del problema.
Esto permitirá definir un mismo diagramas, en
distintos niveles de detalle (ver figura 9):
Detalles suprimidos
f
i
g
u
r
a
Detalle a nivel de análisis
Detalles a nivel de implementación
Figura 9: Clases en distintos niveles de detalle [27]
B.1.1.1 Compartimentos adicionales
Es posible agregar compartimentos definidos por el usuario o predefinidos,
para mostrar otras propiedades del modelo como: reglas del negocio,
excepciones, responsabilidades, etc [27].
Un compartimiento adicional, se
señala con un nombre en la parte superior de él, que indique en forma clara
su contenido (ver figura 10).
Los compartimentos para los atributos y
métodos, no necesitan llevar un nombre, aunque pude ser necesario para
evitar ambigüedades, cuando es suprimido uno de ellos (ver figura 10)
194
Apéndice C: UML
figura 10: Clase con compartimentos adicionales [27]
B.1.1.2 Estereotipos
Los estereotipos permiten extender la semántica de algún elemento de UML,
por ejemplo las clases.
Estos permiten definir restricciones adicionales, o
indicar un modo de uso particular.
Para denotar un estereotipo dentro de una clase, se escribe el nombre del
estereotipo entre comillas («»), sobre el nombre de la clase. Por ejemplo, en
la figura 11 tenemos una clase llamada PenTracker, que tiene el estereotipo
«control».
figura 11: Ejemplo de clase con estereotipo [27]
195
Apéndice C: UML
B.1.1.3 Asociaciones
Para representar las asociaciones de dos clases, utilizamos una línea continua
que las une. En cada extremo de la asociación colocamos la multiplicidad y el
rol que ocupa la clase en la asociación.
El nombre de la asociación lo
colocamos a lo largo de la línea pudiendo indicar la dirección en la que se
debe leer el nombre con una punta de flecha triangular negra. Cuando la
asociación posee atributos, entonces creamos una clase de asociación, la cual
es indicada por una línea punteada que une la asociación a su clase (ver
figura 12).
Nombre Asociación
Multiplicida
Nombre del Rol
Clase Asociación
Autoasociación
figura 12: Ejemplo de Asociaciones entre clases [27] [39]
Una clase puede estar asociada consigo misma.
autoasociación.
En UML, esto se llama
En el ejemplo anterior, tenemos una autoasociación en la
clase trabajo.
B.1.1.4 Agregación y composición
Para la agregación utilizamos un rombo en blanco y para la composición un
rombo negro, en el extremo correspondiente al compuesto, es decir, a la
clase que posee a los componentes.
Por ejemplo, consideremos la siguiente
relación de agregación entre un Polígono y un Punto:
196
Apéndice C: UML
0..*
Poligono
Punto
3..*
figura 13: Ejemplo de agregación
Un polígono, posee 3 o más puntos que son sus vértices, y un punto puede
pertenecer a muchos polígonos o a ninguno.
En la composición, la multiplicidad en el extremo del compuesto puede ser
como máximo una. Por ejemplo, veamos la relación de composición entre
una Bicicleta y sus partes:
1
Pedal
1
Bicicleta
2
2
Freno
1
2
1
Rueda
Marco
1
Asiento
1
Manubrio
figura 14: Ejemplo de composición
B.1.1.5 Generalización
Para la generalización dibujamos como una flecha desde el hijo hacia el
padre, utilizando un triángulo blanco en la punta. Por ejemplo, consideremos
la siguiente jerarquía de generalización, con empleado como superclase y
con las subclases gerente y vendedor (ver figura 15):
197
Apéndice C: UML
Empleado
Gerente
Vendedor
figura 15: Ejemplo generalización
B.1.1.6 Restricciones y comentarios
Una restricción es una expresión encerrada entre llaves que impone ciertas
condiciones al modelo. Las restricciones pueden ser expresadas utilizando el
lenguaje natural, notación de teoría de conjuntos, lenguajes de restricciones
o lenguajes de programación. Para los comentarios se utilizan un rectángulo
que tiene doblada la esquina superior derecha, pero también en ellos
podemos incluir restricciones (ver figura 16).
figura 16: Ejemplo de restricciones y comentarios [39]
198
Apéndice C: UML
B.1.2 Diagrama de colaboración
Los diagramas de colaboración nos permiten mostrar como interactúan los
objetos de las distintas clases para implementar una operación.
En un
diagrama,
en
solamente
mostramos
los
objetos
que
implementación de la operación, el resto se omite.
participan
la
La notación de estos
diagramas se compone de:
•
Objetos participantes
•
Paso de mensajes
•
Relaciones entre los objetos.
•
Roles de clasificación
•
Roles de asociación.
Los objetos participantes son representados por un rectángulo, con el
nombre del objeto, seguido por dos puntos (:) y el rol de clasificación que es
el nombre de la clase del objeto, subrayado. El rol de asociación describe un
enlace dentro de una colaboración. Los mensajes se muestran como flechas,
ligadas a las líneas de la relación, que conectan a los objetos. La secuencia
de mensajes la indicamos con número secuenciales que preceden a las
descripciones del mensaje. Ejemplo:
199
Apéndice C: UML
B.1.3 Para Más información.
si necesita más información revise las referencia bibliográfica [6], [11], [27],
[37] y [38].
200
Apéndice C: Código Fuente del
Prototipo y Pantallas
Código Fuente
C.1 Creación de tipos
Los tipos serán mostrados en el orden que deben ser creados (CREATE
TYPE). Como no podemos utilizar un tipo si este no está creado, debemos
crear primero todos los tipos, y después sus cuerpos.
Pero, por motivos
didácticos hemos agrupado la creación de un tipo con la de su cuerpo,
aunque esto causaría errores de compilación.
C.1.1 array_caudal.
Este es un tipo distinto que define un arreglo de seis elementos del tipo
number.
CREATE OR REPLACE TYPE array_caudal AS VARRAY(6) OF NUMBER
/
show errors
C.1.2 arr_caudales
Este tipo almacena los caudales de octubre a marzo.
ATRIBUTOS
Nombre
Descripción
Caudal
Arreglo para los caudales de octubre a marzo (6 elementos)
del tipo arr_caudal
METODOS
Nombre
Descripción
setCaudal(v,m)
Modifica la posición M del arreglo caudal con el valor V
getCaudal(m):num Retorna el valor de la posición m del arreglo caudal
init()
inicializa el arreglo con valor 0 para cada elemento
CÓDIGO FUENTE
202
Código Fuente
CREATE OR REPLACE TYPE arr_caudales as OBJECT
(
-- atributos
caudal array_caudal,
-- métodos
MEMBER PROCEDURE setCaudal(v IN NUMBER,m IN NUMBER),
MEMBER FUNCTION getCaudal(m IN NUMBER) RETURN NUMBER,
MEMBER PROCEDURE init
)
/
show errors
CREATE OR REPLACE TYPE BODY arr_caudales AS
-- modifica la posición M del arreglo caudales con el valor V
MEMBER procedure setCaudal(v IN NUMBER,m IN NUMBER) IS
BEGIN
IF (m<=6) and (m>=1) then
caudal(m) := v;
else
RAISE_APPLICATION_ERROR(-21100,'indice Fuera
de Rango');
end if;
END setCaudal;
-- Retorna el valor v de la posición m
MEMBER FUNCTION getCaudal(m IN NUMBER) RETURN NUMBER
BEGIN
RETURN (caudal(m));
END getCaudal;
IS
-- pone en cero el arreglo
MEMBER Procedure init IS
BEGIN
FOR i IN 1..6 LOOP
caudal(i):=0;
END LOOP;
END init;
END;
/
show errors
203
Código Fuente
C.1.3 Punto
Este tipo almacena un punto de coordenadas (x,y)
ATRIBUTOS
Nombre
Descripción
X
Coordenada x del punto.
Y
Coordenada y del punto.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Punto as OBJECT
(
X
NUMBER, --coordenada x del punto
Y
NUMBER
--coordenada y del punto
)
/
show errors
C.1.4 arr_puntos
Crea un tipo de arreglo de 100.000 puntos.
CREATE OR REPLACE TYPE
/
show errors
arr_puntos AS VARRAY(100000) OF PUNTO
C.1.5 Polilinea
Este tipo almacena un conjunto de puntos que forman una polilínea (varios
trazos de línea recta unidos)
ATRIBUTOS
Nombre
Descripción
LosPuntos
Arreglo para almacenar los vértices que forman la polilinea
Npuntos
Entero que indica el número de vértices
METODOS
Nombre
Descripción
INIT()
Inicializa la estructura.
AddP(p)
Agrega el punto p al final del arreglo LosPuntos.
AddP(p,i)
Agrega el punto p en la posición i del arreglo LosPuntos.
Desplazando los puntos desde i hasta el final.
indexOf(P):NUM
Devuelve la posición del punto p.
204
Código Fuente
GETP(i):punto
Devuelve el punto de la posición i.
SETP(p,i)
Remplaza el punto que esta en i con p
DELP(i)
Borra el punto que está en i, desplazando los demás puntos
a la izquierda para eliminar el hueco
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Polilinea as OBJECT
(
-- atributos
LOSPUNTOS
ARR_PUNTOS,
NPUNTOS
NUMBER,
ESTILO
NUMBER,
-- métodos
MEMBER PROCEDURE INIT,
MEMBER PROCEDURE ADDP(p in Punto),
EMBER PROCEDURE ADDP(p in Punto,i in number),
MEMBER FUNCTION indexOf(P in punto) RETURN NUMBER,
MEMBER FUNCTION GETP(i in number) RETURN PUNTO,
MEMBER PROCEDURE SETP(p in Punto,i in number),
MEMBER PROCEDURE DELP(i in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Polilinea AS
MEMBER PROCEDURE init IS
BEGIN
NPUNTOS
:= 0;
LOSPUNTOS := ARR_PUNTOS(NULL);
ESTILO
:= 1;
END init;
MEMBER PROCEDURE ADDP(p in Punto) IS
BEGIN
IF ((p<>null)and(NPUNTOS <= 100000)) then
NPUNTOS := NPuntos + 1;
lospuntos.extend; --agrega un casillero null al final
LosPuntos(NPUNTOS):= P;
ELSE
RAISE_APPLICATION_ERROR(-21000,'Error al insertar el
punto');
END IF;
END ADDP;
MEMBER PROCEDURE ADDP(p in Punto,i in number) IS
cont number := npuntos;
BEGIN
IF ((P<>null)and((NPUNTOS <= 100000)and((i<=cont)
and (i>=1)))) then
NPUNTOS := NPuntos +1;
lospuntos.extend;
205
Código Fuente
ELSE
END IF;
END ADDP;
while cont>=i loop
LosPuntos(cont+1):=LosPuntos(cont);
cont := cont - 1;
end loop;
LosPuntos(i):=P;
RAISE_APPLICATION_ERROR(-21001,'Error al insertar
el punto');
MEMBER FUNCTION indexOf(P in punto) RETURN NUMBER IS
cont number:=1;
BEGIN
While (cont<=NPUNTOS) and ((P.x<>LosPuntos(cont).x)
or (P.y<>LosPuntos(cont).y)) loop
cont := cont + 1;
end loop;
if cont>NPUNTOS THEN
return(-1);
else
return(cont);
end if;
END INDEXOF;
MEMBER FUNCTION GETP(i in number) RETURN PUNTO IS
BEGIN
return(LosPuntos(i));
END GETP;
MEMBER PROCEDURE SETP(p in Punto,i in number) is
BEGIN
LosPuntos(I) := P;
END SETP;
MEMBER PROCEDURE DELP(i in number) IS
cont number := i;
BEGIN
IF (i<=npuntos) and (i>=1) then
while cont<npuntos loop
LosPuntos(cont):=LosPuntos(cont+1);
cont := cont + 1;
end loop;
NPUNTOS := NPuntos - 1;
lospuntos.trim;--elimina el ultimo elemento
ELSE
RAISE_APPLICATION_ERROR(-21001,'indice fuera
de rango');
END IF;
END DELP;
END;
/
show errors
206
Código Fuente
C.1.6 Cuadrado
Cuadrado representado por sus cuatro vértices
ATRIBUTOS
Nombre
Descripción
a
Punto del extremo superior izquierdo del cuadrado
b
Punto del extremo superior derecho del cuadrado
c
Punto del extremo inferior izquierdo del cuadrado
d
Punto del extremo inferior derecho del cuadrado
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Cuadrado as OBJECT
(
--propiedades
a
PUNTO,
b
PUNTO,
c
PUNTO,
d
PUNTO
)
/
show errors
C.1.7 Elipse
Elipse representada por su centro, ancho (paralelo al eje x) y su alto (paralelo al
eje Y).
ATRIBUTOS
Nombre
Descripción
Centro
Punto que indica el centro de la elipse.
Ancho
Entero que indica el ancho de la elipse.
Alto
Entero que indica el alto de la elipse.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE elipse as OBJECT
(
--propiedades
Centro
PUNTO,
ANCHO
NUMBER,
ALTO
NUMBER
)
207
Código Fuente
/
show errors
C.1.8 Triangulo
Triangulo representado por sus tres vértices.
ATRIBUTOS
Nombre
Descripción
a
Punto que representa el vértice superior del triángulo
b
Punto que representa el vértice inferior izquierdo del
triangulo
c
Punto que representa el vértice inferior derecho del
triangulo
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Triangulo as OBJECT
(
--propiedades
a
PUNTO,
b
PUNTO,
c
PUNTO
)
/
show errors
208
Código Fuente
C.1.9 Graf_flujo
Este tipo representa un flujo genérico
ATRIBUTOS
Nombre
Descripción
pl
Arreglo para almacenar los vértices que forman el flujo.
Estilo
Entero que indica el estilo de dibujo del flujo, que puede ser
gruesa=0, simple=1 doble=2
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Graf_flujo as OBJECT
(
Pl
ARR_PUNTOS,
Estilo
NUMBER
)
/
show errors
C.1.10 graf_cent_hidro
Este objeto representa los atributos gráficos de una central hidroeléctrica
ATRIBUTOS
Nombre
Descripción
PL1
Polilínea que representa al canal de entrada
PL2
Polilínea que representa al canal se salida
CUAD
Cuadrado que representa a la central hidroeléctrica.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE graf_cent_hidro as OBJECT
(
--atributos
PL1
POLILINEA,--canal de entrada
PL2
POLILINEA,--canal salida
CUAD
Cuadrado --representa el cuadrado central
)
/
show errors
209
Código Fuente
C.1.11 graf_nodo
Representación gráfica de un nodo
ATRIBUTOS
Nombre
Descripción
Elip
Elipse que representa al nodo
CÓDIGO FUENTE
CREATE OR REPLACE TYPE graf_nodo as OBJECT
(
Elip Elipse
)
/
show errors
C.1.12 graf_emb
Representación gráfica de un embalse
ATRIBUTOS
Nombre
Descripción
TR
Triángulo que representa al embalse
CÓDIGO FUENTE
CREATE OR REPLACE TYPE graf_emb as OBJECT
(
TR
TRIANGULO
)
/
show errors
C.1.13 graf_Cuenca
Supertipo de las clases Graf_emb, Graf_flujo, Graf_nodo y Graf_Cent_Hidro,
que son las representaciones gráficas de los objetos de la cuenca.
ATRIBUTOS
Nombre
Descripción
ColorLinea
Indica el color de la figura.
Tipo
Entero que indica el tipo concreto de gráfico
GFL
Almacena un objeto del tipo Graf_Flujo.
GCH
Almacena un objeto del tipo Graf_Cent_hidro.
210
Código Fuente
GNO
Almacena un objeto del tipo Graf_nodo
GEM
Almacena un objeto del tipo Graf_emb
CÓDIGO FUENTE
CREATE OR REPLACE TYPE graf_Cuenca as OBJECT
(
ColorLinea Varchar(15),
Tipo
Number,
GFL
Graf_Flujo,
GCH
Graf_Cent_Hidro,
GNO
Graf_Nodo,
GEM
Graf_Emb
)
/
show errors
C.1.14 Cuenca
Este tipo almacena los datos de una cuenca
ATRIBUTOS
Nombre
Descripción
Codigo
Código de la cuenca
Nombre
Nombre de la cuenca
METODOS
Nombre
Descripción
simular()
Realiza la simulación de la cuenca
CÓDIGO FUENTE
CREATE OR REPLACE TYPE cuenca as OBJECT
(
--propiedades
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
--metodos
MEMBER PROCEDURE SIMULAR
)
/
show errors
CREATE OR REPLACE TYPE BODY CUENCA AS
MEMBER PROCEDURE SIMULAR IS
-- cursor con los nodos pertenecientes a la cuenca
CURSOR NODO_C (cod varchar2) IS
SELECT ROWID FROM TBL_NODO N
211
Código Fuente
WHERE N.MYCUENCA=(SELECT REF(C) FROM TBL_CUENCA C WHERE
C.CODIGO=COD)
ORDER BY N.ORDEN()FOR UPDATE;
nodo_rec
nodoObj
n
i
fecha
UROWID;
nodo;
number;
number;
varchar2(80);
BEGIN
FOR I IN 1..6 LOOP -– recorre cada uno de los meses de la
-- simulación
open NODO_C(codigo);
LOOP
FETCH NODO_C INTO NODO_rec;
exit when NODO_C%NOTFOUND;
SELECT VALUE(e) INTO nodoObj FROM TBL_NODO e WHERE
ROWID=NODO_rec;
if NodoObj is not null then
NodoObj.DistribCaudal(i);
end if;
-- actualiza el nodo persistente con el nodo
transitorio NodoObj utilizado para
UPDATE TBL_nodo e SET e=NodoObj WHERE
ROWID=NODO_rec;
COMMIT;
END LOOP;
close NODO_C;
END LOOP; -- fin del for
COMMIT;
END SIMULAR;
END;
/
show errors
212
Código Fuente
C.1.15 Nodo
Este tipo es la abstracción de un nodo de la cuenca.
ATRIBUTOS
Nombre
Descripción
Codigo
Código del nodo
Caudales
Arreglo con los caudales de entrada para cada mes de la
simulación.
Graf
Almacena los atributos gráficos del nodo
MyCuenca
Almacena una referencia al nodo al que pertenece.
METODOS
Nombre
Descripción
orden():num
Indica la posición que ocuparía el nodo, si ordenamos a
todos los nodos existentes
DistribuirCaudal(m) Calcula el total de caudal de entrada y lo distribuye entre
todos los objetos que extraen su caudal, el caudal de
entrada es almacenado en caudales(m).
CÓDIGO FUENTE
CREATE OR REPLACE
(
--atributos
CODIGO
COTA
CAUDALES
GRAF
MYCUENCA
TYPE nodo as OBJECT
VARCHAR2(40) ,
NUMBER
,
ARR_CAUDALES ,
GRAF_NODO
,
REF CUENCA ,
-- métodos
MAP MEMBER FUNCTION Orden RETURN NUMBER,
MEMBER PROCEDURE DistribCaudal(m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY nodo AS
--convierte el código de la forma "NO I-J" en el Num real I.J
MAP MEMBER function orden RETURN number IS
strCod varchar2(40);
begin
strCod:=REPLACE(SUBSTR(LTRIM(RTRIM(codigo)),4),'-','');
RETURN (TO_NUMBER(strCod));
end orden;
213
Código Fuente
-- Distribuye el caudal de entrada al nodo por todas las
-- salidas que tenga
MEMBER procedure distribCaudal(m IN number) is
-- definición de variables
entrada
number:=0;
demanda
number:=0;
resto
number:=0;
n
number:=0;
fl_rec
UROWID;
emb_rec
UROWID;
fl
flujo;
emb
Embalse;
valor
number:=0;
--definición de cursores
CURSOR Emb_c(COD VARCHAR2) IS
select ROWID from tbl_emb e where e.mynodo=
(select Ref(n) from tbl_nodo n where
n.codigo=COD) FOR UPDATE;
CURSOR flujo_cursor(COD VARCHAR2) IS
select ROWID from tbl_flujo f
where (f.tipo!=1)and (f.nodo_ini=
(select Ref(n) from tbl_nodo n where
n.codigo=COD)) FOR UPDATE;
-- Esta función calcula las entradas del nodo
function caudalEntradas(mes in number,cod varchar2)
return number is
CURSOR ENT_C(M NUMBER,C VARCHAR2) IS
select f.salida(M),rowid from tbl_flujo f
where f.tipo!=2 and f.nodo_fin=(select ref(n)
from tbl_nodo n where n.codigo=c);
ent
number:=0;
valor number:=0;
begin
open ENT_C(mes,cod);
loop
FETCH ENT_C INTO valor,id;
exit when ENT_C%NOTFOUND;
ent:=ent + valor;
end loop;
close ENT_C;
return( ent );
end;
-- Esta función calcula las demandas del nodo
function demandaAlNodo(e in number,mes in number,
cod in varchar2)return number is
CURSOR DEM_C(ent number,m number,c VARCHAR2) is
select f.demanda(ent,m) from tbl_flujo f
where f.tipo!=1 and f.nodo_ini=(select ref(n) from
tbl_nodo n where n.codigo=cod);
214
Código Fuente
valor number:=0;
dem
number:=0;
begin
end;
BEGIN
open DEM_C(e,mes,cod);
loop
FETCH DEM_C INTO valor;
exit when DEM_C%NOTFOUND;
dem:=dem + valor;
end loop;
close DEM_C;
return(dem);
entrada:=caudalEntradas(m,codigo);
demanda:=demandaAlNodo(Entrada,m,codigo);
caudales.setCaudal(entrada,m);
-- si el nodo tiene un embalse entonces no puede tener
-- otras salidas. así que todo el caudal de entrada va
-- para el embalse.
n:=0; -- numero de embalses
open EMB_C(codigo);
loop
fetch emb_c into emb_rec;
exit when emb_c%notfound;
n:=n+1;
end loop;
close EMB_C;
if n>0 then -- si el nodo tiene uno o más embalses
open EMB_C(codigo);
loop
FETCH EMB_C INTO EMB_rec;
exit when EMB_C%NOTFOUND;
SELECT VALUE(e) INTO EMB
FROM TBL_EMB e
WHERE ROWID=EMB_rec;
valor:=entrada/N;
EMB.entrada(valor, M);
UPDATE TBL_EMB e SET e=emb WHERE ROWID=EMB_rec;
COMMIT;
end loop;
close EMB_C;
else
-- SI NO TIENE EMBALSE -> PROCESAR SUS FLUJOS.
-- entregar caudales a flujos demandantes, en
-- forma proporcional a sus demandas.
n:=0;
if demanda > 0 then --si hay flujos demandantes.
open flujo_cursor(codigo);
215
Código Fuente
loop
FETCH flujo_cursor INTO fl_rec;
exit when flujo_cursor%NOTFOUND;
SELECT VALUE(F) INTO FL
FROM TBL_FLUJO F
WHERE ROWID=fl_rec;
if fl.demanda(entrada,m) > 0 then
valor:=entrada*(fl.demanda(entrada,m)/
demanda );
fl.entrada(valor,M);
UPDATE TBL_FLUJO F SET F=FL
WHERE ROWID=fl_rec;
COMMIT;
Else
n:=n+1;--cuento el numero de flujos que
--no demandan caudal.
end if;
end loop;
close flujo_cursor;
else -- si no hay demanda, es necesario contar los
-- flujos que no demandan caudal
open flujo_cursor(codigo);
loop
FETCH flujo_cursor INTO fl_rec;
exit when flujo_cursor%NOTFOUND;
SELECT VALUE(F) INTO FL FROM TBL_FLUJO F
WHERE ROWID=fl_rec;
if fl.demanda(entrada,m) = 0 then
n:=n+1; -- cuento el numero de flujos
-- que no demandan caudal.
end if;
end loop;
close flujo_cursor;
end if;
-- caudal restante para los flujos no demandantes
-- como los ríos
Resto:=entrada - demanda;
if resto < 0 then
resto:=0;
end if;
if N >0 then --si existen flujos no demandantes.
open flujo_cursor(codigo);
loop
FETCH flujo_cursor INTO fl_rec;
exit when flujo_cursor%NOTFOUND;
SELECT VALUE(F) INTO FL
FROM TBL_FLUJO F WHERE ROWID=fl_rec;
if fl.demanda(entrada,m) = 0 then
valor:=Resto/N;
fl.entrada(valor,M);
UPDATE TBL_FLUJO F SET F=FL WHERE
ROWID=fl_rec;
COMMIT;
216
Código Fuente
end if;
end loop;
close flujo_cursor;
end if;
end if;
END distribCaudal;
END;
/
show errors
C.1.16 Rio
Este tipo nos permite almacenar los datos generales de un Río.
ATRIBUTOS
Nombre
Descripción
codigo
Código que identifica al río
nombre
Nombre del río
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Rio as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50)
)
/
show errors
C.1.17 Hoya_inter
Este tipo es la abstracción de una Hoya Intermedia
ATRIBUTOS
Nombre
Descripción
codigo
Código que identifica la hoya intermedia
nombre
Nombre de la hoya intermedia
Ref_rio_aportante Referencia al río al que pertenece la hoya intermedia
Caudales
Arreglo con los caudales que aporta la hoya intermedia en
cada mes de la simulación.
METODOS
217
Código Fuente
Nombre
Descripción
ToVarchar2():cad Entrega una cadena de caracteres formada por la palabra
“hoya_Inter“
concatenado
con
el
código
de
la
hoya
intermedia
salida(m):num
Entrega el caudal que es aportado por la hoya intermedia a
un nodo en el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Hoya_inter as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
REF_RIO_APORTE
REF RIO ,
CAUDALES
ARR_CAUDALES,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER
)
/
show errors
CREATE OR REPLACE TYPE BODY Hoya_inter AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Hoya_inter '||codigo);
end toVarchar2;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return(Caudales.getcaudal(m));
END Salida;
END;
/
show errors
218
Código Fuente
C.1.18 Regimen_Natural
Este tipo es la abstracción de un régimen natural.
ATRIBUTOS
Nombre
Descripción
codigo
Código que identifica al régimen natural
nombre
Nombre del régimen natural
Caudales
Arreglo con los caudales que aporta el régimen natural en
cada mes de la simulación.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena de caracteres formada por la palabra
“Regimen_Natural “ concatenado con el código del régimen
natural.
salida(m):num
Entrega el caudal que es aportado por el régimen natural a
un nodo en el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Regimen_Natural as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
CAUDALES
ARR_CAUDALES,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER
)
/
show errors
CREATE OR REPLACE TYPE BODY Regimen_Natural AS
MEMBER FUNCTION toVarchar2 return varchar2 is
BEGIN
return('Regimen_Natural'||codigo);
END toVarchar2;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return(Caudales.getcaudal(m));
END Salida;
END;
/
219
Código Fuente
show errors
C.1.19 Salida_Emb
Este tipo es la abstracción de una salida de un embalse
ATRIBUTOS
Nombre
Descripción
tipo
Tipo de la salida de embalse, que puede ser Ee,Er,F,R,G
codigoemb
Código del embalse al que pertenece el flujo
Caudales
Arreglo con los caudales que recibe la salida desde el
embalse en cada mes de la simulación.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena de caracteres formada por la cadena
“Salida_Emb “, concatenado con CodigoEmb”-“tipo.
salida(m):num
Entrega el caudal que aporta la salida del embalse a un
nodo para el mes m de la simulación.
CÓDIGO FUENTE
CREATE OR REPLACE
(
--atributos
Tipo
CODIGOEMB
CAUDALES
--métodos
MEMBER FUNCTION
MEMBER FUNCTION
)
/
show errors
TYPE Salida_Emb as OBJECT
VARCHAR2(2) ,
VARCHAR2(40),
ARR_CAUDALES,
--Ee,Er,F,R,G
toVarchar2 return varchar2,
SALIDA(m in number) RETURN NUMBER
CREATE OR REPLACE TYPE BODY Salida_Emb AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Salida_Emb '||codigoEMB||'-'||tipo);
end toVarchar2;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return(Caudales.getcaudal(m));
END Salida;
END;
220
Código Fuente
/
show errors
C.1.20 Aportante
Esta es la implementación mediante agregación del supertipo de: Hoya_Inter,
Regimen_natural, Salida_emb.
ATRIBUTOS
Nombre
Descripción
tipo
Número que indica el tipo concreto de un objeto aportante,
que
puede
ser:
1=Hoya_Inter,
2=Regimen_natural,
3=Salida_emb.
HI
Almacena un objeto del tipo Hoya_Inter.
RN
Almacena un objeto del tipo Regimen_Natural.
SE
Almacena un objeto del tipo Salida_Emb.
METODOS
Nombre
Descripción
ToVarchar2():cad Invoca al método ToVarchar2(), sobre HI, RN o SE
dependiendo del tipo correspondiente.
salida(m):num
Invoca al método salida(), sobre HI, RN o SE dependiendo
del tipo correspondiente.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Aportante as OBJECT
(
--atributos
Tipo
NUMBER,
HI
Hoya_inter,
RN
Regimen_Natural,
SE
Salida_Emb,
--metodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER
)
/
show errors
CREATE OR REPLACE TYPE BODY Aportante AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
IF tipo=1 THEN
221
Código Fuente
return(HI.toVarchar2());
ELSIF tipo=2 THEN
return(RN.toVarchar2());
ELSIF tipo=3 THEN
return(SE.toVarchar2());
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
end toVarchar2;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
IF tipo=1 THEN
return(HI.salida(m));
ELSIF tipo=2 THEN
return(RN.salida(m));
ELSIF tipo=3 THEN
return(SE.salida(m));
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END Salida;
END;
/
show errors
C.1.21 Canal
Esta es la abstracción de un canal
ATRIBUTOS
Nombre
Descripción
codigo
Código del canal
nombre
Nombre del canal
cap_conducción
Cantidad máxima de M3 por segundo que es posible
transportar por el canal.
Eficiencia
Porcentaje que indica la cantidad de agua de salida con
referencia a la entrada.
A
Máximo caudal posible de captar
B
Caudal mínimo que debe tener el río para que el canal
pueda captar agua.
Si el caudal del río es menor a B,
entonces el caudal captado es cero.
C
Caudal del río que hace que el caudal captado sea máximo.
222
Código Fuente
Caudales
Arreglo con los caudales de entrada al canal.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena compuesta por “Canal “ concatenado
con Codigo.
salida(m):num
Entrega la cantidad que el canal aporta al nodo final en el
mes m
Demanda(caudal,m) Entrega la cantidad de agua que demanda el canal sobre el
caudal del río pasado como parámetro. El parámetro m, es
pasado por compatibilidad del método con los otros tipos
del mismo supertipo.
Entrada(caudal,m) Cantidad de caudal que entra en el canal desde el nodo
inicial en el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Canal as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
CAP_CONDUCION
NUMBER
,
EFICIENCIA
NUMBER
,
A
NUMBER
,
B
NUMBER
,
C
NUMBER ,
CAUDALES
ARR_CAUDALES,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Canal AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Canal '||codigo);
end;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
223
Código Fuente
IF caudal<=b THEN
return(0);
ELSIF caudal>c THEN
return(a);
ELSE
-- Calcula el valor del caudal captado en base a la
-- ecuación de la recta que pasa por los punto (b,0) y
-- (c,a).
return(((A / (c-b))*(caudal - c))+A);
END IF;
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
CAUDALES.SetCaudal(caudal,m);
END ENTRADA;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return((Caudales.getcaudal(m)*Eficiencia)/100);
END Salida;
END;
/
show errors
C.1.22 Tramo
Esta es la abstracción de un tramo de río
ATRIBUTOS
Nombre
Descripción
MyRio
Referencia al río al cual corresponde el tramo
Num_Tramo
Número del tramo. La numeración comienza desde aguas
arriba hacia aguas abajo.
Caudales
Arreglo con los caudales de entrada al tramo de río
224
Código Fuente
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega
una
cadena
compuesta
por
“Tramo
Nº”,
concatenado con el número del tramo y “del río “ seguido
del nombre del río.
salida(m):num
Caudal aportado al nodo final por el tramo de río.
Demanda(caudal,m) Siempre devuelve cero, puesto que un tramo de río no
tiene una demanda de caudal.
Los parámetros son
mantenidos por compatibilidad.
Entrada(caudal,m) Cantidad de caudal que entra en el tramo de río desde el
nodo inicial en el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Tramo as OBJECT
(
--atributos
MYRIO
Ref RIO ,
NUM_TRAMO
NUMBER
,
CAUDALES
ARR_CAUDALES,
--metodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Tramo AS
MEMBER FUNCTION toVarchar2 return varchar2 is
nomrio
varchar2(40);
BEGIN
select r.codigo into nomrio
from tbl_rio r where ref(r)=myrio;
return('Tramo N '||to_char(num_tramo)||
' del rio'||nomrio);
END toVarchar2;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
return(0);
END DEMANDA;
225
Código Fuente
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
CAUDALES.SetCaudal(caudal,m);
END ENTRADA;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return(Caudales.getcaudal(m));
END Salida;
END;
/
show errors
C.1.23 Central_hidro
Este tipo es la abstracción de una central hidroeléctrica.
ATRIBUTOS
Nombre
Descripción
codigo
Código de la central hidroeléctrica
nombre
Nombre de la central hidroeléctrica
caudal_max_gen
Caudal de entrada que permite la máxima generación
hidroeléctrica por parte de la central.
caudal_min
Caudal mínimo de entrada a la central hidroeléctrica que
permite su funcionamiento.
Caudales
Arreglo
con
los
caudales
de
entrada
a
la
central
hidroeléctrica.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena compuesta por “Central Hidro ”,
concatenado con el código de la central.
salida(m):num
Caudal aportado al nodo final por la central en el mes m.
Kw(m):num
Función que entrega la energía generada para el mes m.
Por falta de información, este método no utiliza la fórmula
correcta para calcular los KW generados por la central.
Demanda(caudal,m) La demanda de la central es constante, y corresponde a
cauda_max_gen.
Entrada(caudal,m) Cantidad de caudal que entra en la central hidroeléctrica
desde el nodo inicial en el mes m.
226
Código Fuente
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Central_hidro as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
CAUDAL_MAX_GEN
NUMBER
,
CAUDAL_MIN
NUMBER
,
CAUDALES
ARR_CAUDALES,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION KW(m in number) RETURN NUMBER,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER,
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Central_hidro as
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Central_hidro '||codigo);
end;
MEMBER FUNCTION KW(m in number) RETURN NUMBER is
Begin
--NOTA: ESTA FORMULA NO ES CORRECTA.
return(Caudales.getcaudal(m)*1.86);
end KW;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
return(Caudal_max_gen);
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
CAUDALES.SetCaudal(caudal,m);
END ENTRADA;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
return(Caudales.getcaudal(m));
END Salida;
END;
/
show errors
227
Código Fuente
C.1.24 Apor_extrac
Este tipo corresponde a la implementación del supertipo de: Canal, Tramo y
Central_Hidro.
ATRIBUTOS
Nombre
Descripción
Tipo
Número que indica el tipo concreto que está almacenado.
Los valores que puede tomar son: 1=Canal, 2=Tramo,
3=Central_hidro
CA
Almacena una instancia de Canal.
TR
Almacena una instancia de Tramo.
CH
Almacena una instancia de Central_hidro.
METODOS
Nombre
Descripción
ToVarchar2():cad Invoca a la función ToVarchar2() sobre el atributo CA, TR o
CH dependiendo del atributo tipo
salida(m):num
Invoca a la función salida(m) sobre el atributo CA, TR o CH
dependiendo del atributo tipo
Demanda(caudal,m) Invoca a la función demanda(caudal,m) sobre el atributo
CA, TR o CH dependiendo del atributo tipo
Entrada(caudal,m) Invoca a la función Entrada(caudal,m) sobre el atributo CA,
TR o CH dependiendo del atributo tipo
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Apor_extrac as OBJECT
(
--atributos
Tipo
NUMBER,
CA
Canal,
TR
Tramo,
CH
Central_hidro,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
228
Código Fuente
)
/
show errors
CREATE OR REPLACE TYPE BODY Apor_extrac AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
IF
tipo=1 THEN
return(CA.toVarchar2());
ELSIF tipo=2 THEN
return(TR.toVarchar2());
ELSIF tipo=3 THEN
return(CH.toVarchar2());
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
end toVarchar2;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
IF
tipo=1 THEN
return(CA.demanda(caudal,m));
ELSIF tipo=2 THEN
return(TR.demanda(caudal,m));
ELSIF tipo=3 THEN
return(CH.demanda(caudal,m));
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
IF
tipo=1 THEN
CA.ENTRADA(caudal,m);
ELSIF tipo=2 THEN
TR.ENTRADA(caudal,m);
ELSIF tipo=3 THEN
CH.ENTRADA(caudal,m);
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END ENTRADA;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
IF
tipo=1 THEN
return(CA.salida(m));
ELSIF tipo=2 THEN
return(TR.salida(m));
ELSIF tipo=3 THEN
229
Código Fuente
ELSE
return(CH.salida(m));
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END Salida;
END;
/
show errors
C.1.25 Cap_agua_Pot
Este tipo representa la abstracción de una captación de agua potable
Central_Hidro.
ATRIBUTOS
Nombre
Descripción
codigo
Código de la captación de agua potable
nombre
Nombre de la captación de agua potable.
Caudal_de_extrac Arreglo con la demanda de extracción para cada mes de la
simulación.
Caudales
Caudales extraídos del nodo inicial para cada mes de la
simulación.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena compuesta por “Cap_agua_Pot ”,
concatenado con el código de la captación de agua potable.
Demanda(caudal,m) Entrega la cantidad de agua demandada, según el arreglo
caudal_de_extrac.
Entrada(caudal,m) Permite asignar el caudal captado desde el nodo inicial en
el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Capt_Agua_Pot as OBJECT
(
--atributos
CODIGO
VARCHAR2(40),
NOMBRE
VARCHAR2(50),
Caudal_de_extrac
ARR_CAUDALES,
230
Código Fuente
CAUDALES
ARR_CAUDALES,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Capt_Agua_Pot AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Capt_agua_Pot '||codigo);
end;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
return(Caudal_de_extrac.getCaudal(m));
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
CAUDALES.SetCaudal(caudal,m);
END ENTRADA;
END;
/
show errors
C.1.26 Extracción
Este tipo corresponde a la implementación del supertipo de cap_agua_pot. Este
tipo representa a todos los flujos que extraen caudales del nodo.
ATRIBUTOS
Nombre
Descripción
Tipo
Número que indica el tipo concreto que está almacenado.
Los valores que puede tomar son: 1=Cap_agua_pot
CA
Almacena una instancia de Cap_agua_pot.
METODOS
Nombre
Descripción
231
Código Fuente
ToVarchar2():cad Invoca a la función ToVarchar2() sobre el atributo CA, TR o
CH dependiendo del atributo tipo
Demanda(caudal,m) Invoca a la función Demanda(caudal,m) sobre el atributo
CA
Entrada(caudal,m) Invoca a la función Entrada(caudal,m) sobre el atributo CA
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Extraccion as OBJECT
(
--atributos
Tipo NUMBER,
CA
Capt_Agua_Pot,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Extraccion AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
IF
tipo=1 THEN
return(CA.toVarchar2());
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
end toVarchar2;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
IF tipo=1 THEN
return(CA.demanda(caudal,m));
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
IF tipo=1 THEN
CA.ENTRADA(caudal,m);
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
232
Código Fuente
END ENTRADA;
END;
/
show errors
C.1.27 Flujo
Este tipo corresponde a la implementación del supertipo de: Aportante,
Extraccion y Apor_extrac.
ATRIBUTOS
Nombre
Descripción
Nodo_ini
Referencia al nodo inicial del flujo.
Nodo_fin
Referencia al nodo final del flujo.
Graf
Almacena los atributos gráficos del flujo.
Tipo
Número que indica el tipo concreto que está almacenado.
Los
valores
que
puede
tomar
son:
1=Aportante,
2=extraccion, 3=Apor_extrac
AP
Almacena una instancia de Aportante.
EX
Almacena una instancia de Extraccion.
APEX
Almacena una instancia de Apor_extrac.
METODOS
Nombre
Descripción
ToVarchar2():cad Invoca a la función ToVarchar2() sobre el atributo AP, EX o
APEX dependiendo del atributo tipo
salida(m):num
Invoca a la función salida(m) sobre el atributo AP, EX o
APEX dependiendo del atributo tipo
Demanda(caudal,m) Invoca a la función demanda(caudal,m) sobre el atributo
AP, EX o APEX dependiendo del atributo tipo
Entrada(caudal,m) Invoca a la función Entrada(caudal,m) sobre el atributo AP,
EX o APEX dependiendo del atributo tipo
CÓDIGO FUENTE
CREATE OR REPLACE TYPE Flujo as OBJECT
(
233
Código Fuente
--atributos
NODO_INI
Ref NODO ,
NODO_FIN
Ref NODO ,
GRAF
Graf_Cuenca,
Tipo
NUMBER,
AP
Aportante,
EX
Extraccion,
APEX
Apor_extrac,
--métodos
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER,
MEMBER FUNCTION DEMANDA(caudal in number,m in number)
RETURN NUMBER,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
)
/
show errors
CREATE OR REPLACE TYPE BODY Flujo AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
IF tipo=1 THEN
return(ap.toVarchar2());
ELSIF tipo=2 THEN
return(EX.toVarchar2());
ELSIF tipo=3 THEN
return(APEX.toVarchar2());
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
end toVarchar2;
MEMBER FUNCTION DEMANDA(caudal in number,m in number) RETURN
NUMBER IS
BEGIN
IF
tipo=1 THEN
RAISE_APPLICATION_ERROR(-20111,'No se puede
invocar el método demanda(c,m):n sobre un
tipo Aportante');
ELSIF tipo=2 THEN
return(EX.demanda(caudal,m));
ELSIF tipo=3 THEN
return(APEX.demanda(caudal,m));
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END DEMANDA;
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)IS
BEGIN
IF tipo=1 THEN
RAISE_APPLICATION_ERROR(-20111,'No se puede
invocar el metodo Entrada(c,m) sobre un
tipo Aportante');
234
Código Fuente
ELSIF tipo=2 THEN
EX.ENTRADA(caudal,m);
ELSIF tipo=3 THEN
APEX.ENTRADA(caudal,m);
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END ENTRADA;
MEMBER FUNCTION SALIDA(m in number) RETURN NUMBER IS
BEGIN
IF
tipo=1 THEN
return(AP.salida(m));
ELSIF tipo=2 THEN
RAISE_APPLICATION_ERROR(-20111,'No se puede
invocar el método Salida(m):n sobre un tipo
Extracione');
ELSIF tipo=3 THEN
return(APEX.salida(m));
ELSE
RAISE_APPLICATION_ERROR(-22000,'Tipo inexistente
corregir campo tipo');
END IF;
END Salida;
END;
/
show errors
C.1.28 Embalse
Este tipo es la abstracción de un embalse.
ATRIBUTOS
Nombre
Descripción
codigo
Código del embalse
myNodo
Referencia al nodo en el que está ubicado el embalse.
volumenUtil
Volumen del embalse que puede ser utilizado.
capmax
Capacidad máxima del embalse.
Evap
Almacena la evaporación mensual del embalse
Superficie
Hectarias que abarca el embalse
VolumenTot
Volumen total de caudal en el embalse
Coef
Coeficiente del embalse, que por lo general es 0.7
EntregaMaxPorV
Caudal máximo de salida por válvula.
VolumenInicial
Volumen con el que cuenta el embalse antes de la
simulación.
235
Código Fuente
Curva_alerta
Arreglo con los valores mínimos de caudales para cada mes
de la simulación
Graf
Atributos gráficos del embalse
Caudales
Arreglo con los caudales de entrada para el embalse para
cada uno de los meses de simulación.
Filtraciones
Salida del embalse por concepto de filtraciones
Rebases
Salida del embalse por concepto de rebases
EntregaEner
Salida del embalse para generación hidroeléctrica
EntregaRieg
Salida del embalse por riego
EntregaGen
Salida del embalse que representa al caudal utilizado en la
generación hidroeléctrica en la central al pie del embalse.
METODOS
Nombre
Descripción
ToVarchar2():cad Entrega una cadena formada por “Embalse” concatenado
con el código del embalse.
Entrada(caudal,m) Permite asignar el caudal entregado por el nodo al embalse
en el mes m.
CÓDIGO FUENTE
CREATE OR REPLACE
(
--atributos
CODIGO
MYNODO
VOLUMENUTIL
CAPMAX
EVAP
SUPERFICIE
VOLUMENTOT
COEF
ENTRAGAMAXPORV
VOLUMENINICIAL
CURVA_ALERTA
GRAF
CAUDALES
FILTRACIONES
REBASES
ENTREGAENER
ENTREGARIEG
ENTREGAGEN
TYPE Embalse as OBJECT
VARCHAR2(40)
Ref NODO
,
NUMBER
,
NUMBER
,
NUMBER
,
NUMBER
,
NUMBER
,
NUMBER
,
NUMBER
,
NUMBER
,
ARR_CAUDALES,
GRAF_EMB,
ARR_CAUDALES,
REF FLUJO,
REF
FLUJO,
REF FLUJO
,
REF FLUJO
,
REF FLUJO
,
,
--METODOS
MEMBER FUNCTION toVarchar2 return varchar2,
MEMBER PROCEDURE ENTRADA(caudal in number,m in number)
236
Código Fuente
)
/
show errors
CREATE OR REPLACE TYPE BODY Embalse AS
MEMBER FUNCTION toVarchar2 return varchar2 is
begin
return('Embalse '||codigo);
end toVarchar2;
--Este método no es la forma real en que se opera un –
--embalse.
MEMBER PROCEDURE ENTRADA(caudal in number,m in number) IS
F
number;
R
number;
Ee
number;
Er
number;
Eg
number;
Vac
number:=0;
mes
number;
Procedure entregarCaudal(c in number,m in number,RFL
in ref flujo) is
fl
flujo;
begin
--ENTREGAGEN.caudales.setCaudal(Eg,m)
select value(p) into fl
from tbl_flujo p where ref(p)=RFL;
fl.ap.se.caudales.setCaudal(c,m);
update tbl_flujo p set p= fl
where ref(p)=RFL;
end;
BEGIN
caudales.setCaudal(caudal,M);
if (M = 1) then
Vac := VolumenInicial;
else
mes:=1;
while mes < M loop
Vac :=Vac + caudales.getCaudal(mes);
mes:=mes+1;
end loop;
end if;
R:=(caudal + Vac ) - CapMax;
if (r < 0 ) then
r:=0;
end if;
Vac := caudal - r;
F
:= Vac * 0.005;
Vac := Vac - F;
237
Código Fuente
Ee
Er
Eg
:= Caudal / 3;
:= Caudal / 3;
:= Caudal - Ee
- Er;
entregarCaudal(F,m,FILTRACIONES);
entregarCaudal(R,m,REBASES);
entregarCaudal(Ee,m,ENTREGAENER);
entregarCaudal(Er,m,ENTREGARIEG);
entregarCaudal(Eg,m,ENTREGAGEN);
END entrada;
END;
/
show errors
238
Código Fuente
C.2 Definición de Tablas de objetos
e inserción de instancias
C.2.1 Tabla: tbl_cuenca
Create table tbl_cuenca OF cuenca
(
CODIGO NOT NULL PRIMARY KEY
)
/
show errors
C.2.2 Tabla: tbl_nodo
create table tbl_nodo OF nodo
(
CODIGO NOT NULL PRIMARY KEY,
FOREIGN KEY (myCuenca) REFERENCES tbl_cuenca ON DELETE CASCADE
)
/
show errors
C.2.3 Tabla: tbl_rio
create table tbl_rio OF rio
(
CODIGO NOT NULL PRIMARY KEY
)
/
show errors
C.2.4 Tabla: tbl_Flujo
create table tbl_Flujo
OF Flujo
(
FOREIGN KEY (nodo_ini) REFERENCES tbl_nodo ON DELETE CASCADE,
FOREIGN KEY (nodo_fin) REFERENCES tbl_nodo ON DELETE CASCADE
)
/
show errors
C.2.5 Tabla: tbl_Emb
create table
(
FOREIGN KEY
FOREIGN KEY
FOREIGN KEY
FOREIGN KEY
tbl_Emb OF Embalse
(mynodo) REFERENCES tbl_nodo ON DELETE CASCADE,
(FILTRACIONES) REFERENCES tbl_flujo ON DELETE CASCADE,
(REBASES) REFERENCES tbl_flujo ON DELETE CASCADE,
(ENTREGAENER) REFERENCES tbl_flujo ON DELETE CASCADE,
239
Código Fuente
FOREIGN KEY (ENTREGARIEG) REFERENCES tbl_flujo ON DELETE CASCADE,
FOREIGN KEY (ENTREGAGEN) REFERENCES tbl_flujo ON DELETE CASCADE
)
/
show errors
C.2.6 Inserción de una Cuenca
insert into tbl_cuenca values(cuenca('01','Cuenca del Rio Maule'))
/
C.2.7 Inserción de un Rio
insert into tbl_rio values(rio('R00','Estero [sin nombre]'))
/
C.2.8 Inserción de un Nodo
Insert into tbl_nodo values
(
nodo('NO 1-1',2500,
arr_caudales(array_caudal(0,0,0,0,0,0)),
graf_nodo(elipse(Punto(387,87),39,24)),
(select REF(C) from tbl_cuenca C where c.codigo='01')
)
)
/
C.2.9 Inserción de un Embalse y sus salidas
insert into tbl_emb values
(
embalse('EM1',(select REF(N) from tbl_nodo n where n.codigo='NO 1-1'),
100000,150000,20000,10,150000, 0.7,20000,1000,
arr_caudales(array_caudal(1000,1200,1300,1400,1500,1600)),
GRAF_EMB(TRIANGULO(PUNTO(387,99),PUNTO(354,138),PUNTO(425,138))),
arr_caudales(array_caudal(0,0,0,0,0,0)),null,null,null,null,null
)
)
/
-- insertando las 5 salidas del embalse
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(360,138),
Punto(378,229)),1),null,null,null),1,
aportante(3,null,null,SALIDA_EMB('F','EM1',
arr_caudales(array_caudal(0,0,0,0,0,0)))),
null,null)
)
/
240
Código Fuente
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(375,138),
Punto(382,228)),1),null,null,null),1,
aportante(3,null,null,SALIDA_EMB('Ee','EM1',
arr_caudales(array_caudal(0,0,0,0,0,0)))),
null,null)
)
/
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(387,138),
Punto(387,228)),1),null,null,null),1,
aportante(3,null,null,SALIDA_EMB('R','EM1',
arr_caudales(array_caudal(0,0,0,0,0,0)))),
null,null)
)
/
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(400,138),
Punto(393,228)),1),null,null,null),1,
aportante(3,null,null,SALIDA_EMB('Er','EM1',
arr_caudales(array_caudal(0,0,0,0,0,0)))),
null,null)
)
/
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(417,138),
Punto(399,230)),1),null,null,null),1,
aportante(3,null,null,SALIDA_EMB('G','EM1',
arr_caudales(array_caudal(0,0,0,0,0,0)))),
null,null)
)
/
-- actualizando las referencias en el embalse
update tbl_emb e
set filtraciones=(select REF(f) from tbl_flujo f
where (f.ap.se.codigoemb='EM1')and(f.ap.se.tipo='F'))
WHERE e.codigo='EM1'
/
update tbl_emb e
set Rebases=(select REF(f) from tbl_flujo f
241
Código Fuente
where (f.ap.se.codigoemb='EM1')and(f.ap.se.tipo='R'))
WHERE e.codigo='EM1'
/
update tbl_emb e
set EntregaEner=(select REF(f) from tbl_flujo f
where (f.ap.se.codigoemb='EM1')and(f.ap.se.tipo='Ee'))
WHERE e.codigo='EM1'
/
update tbl_emb e
set EntregaRieg=(select REF(f) from tbl_flujo f
where (f.ap.se.codigoemb='EM1')and(f.ap.se.tipo='Er'))
WHERE e.codigo='EM1'
/
update tbl_emb e
set EntregaGen=(select REF(f) from tbl_flujo f
where (f.ap.se.codigoemb='EM1')and(f.ap.se.tipo='G'))
WHERE e.codigo='EM1'
/
C.2.10 Inserción de un Regimen Natural
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-1'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(432,65),
Punto(398,77)),1),null,null,null),1,aportante(2,null,
Regimen_natural('RN 1-1','Afluentes Laguna Maule',
arr_caudales(array_caudal(5000,6000,7000,7000,8000,2000))),
null),
null,null)
)
/
C.2.11 Inserción de una Hoya Intermedia
insert into tbl_flujo values
(
flujo(null,(select REF(n) from tbl_nodo n where n.codigo='NO 1-5'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(272,391),
Punto(308,391)),1),null,null,null),
1,aportante(1,Hoya_Inter('HI 1-5','-',
(select ref(r) from tbl_rio r where r.codigo='R11'),
arr_caudales(array_caudal(9230,8980,7520,6520,9860,7510))),
null,null),
null,null)
)
/
242
Código Fuente
C.2.12 Inserción de una Captación de Agua Potable
insert into tbl_flujo values
(
flujo((select REF(n) from tbl_nodo n where n.codigo='NO 1-6'),
null,
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(404,366),
Punto(444,382)),1),null,null,null),
2,
null,
EXTRACCION(1,
CAPT_AGUA_POT('CAPT AGUA 01','Captación de agua potable 01',
arr_caudales(array_caudal(8560,7320,6980,5680,9760,1230)),
arr_caudales(array_caudal(0,0,0,0,0,0))))
,null
)
)
/
C.2.13 Inserción de una Central Hidroeléctrica
insert into tbl_flujo values
(
flujo(
(select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
(select REF(n) from tbl_nodo n where n.codigo='NO 1-6'),
graf_cuenca('Negro',2,null,
graf_cent_hidro(polilinea(arr_puntos(Punto(406,243),
Punto(432,257),Punto(432,276)),3,2),
polilinea(arr_puntos(Punto(432,300),
Punto(432,311),Punto(400,351)),3,2),
cuadrado(Punto(420,276),Punto(444,276),
Punto(420,300),Punto(444,300))),null,null),
3,null,null,
apor_extrac(3,null,null,
Central_hidro('CI 1-1','Central los condores',50000,1000,
arr_caudales(array_caudal(0,0,0,0,0,0))
))
)
)
/
C.2.14 Inserción de un Tramo de Rio
insert into tbl_flujo values
(flujo((select REF(n) from tbl_nodo n where n.codigo='NO 1-2'),
(select REF(n) from tbl_nodo n where n.codigo='NO 1-6'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(387,252),
Punto(387,348)),3),null,null,null),3,null,null,
apor_extrac(2,null,Tramo( (select ref(r) from tbl_rio r
where r.codigo='R11'),
2,arr_caudales(array_caudal(0,0,0,0,0,0))),null
))
)
/
243
Código Fuente
C.2.15 Inserción de un Canal
insert into tbl_flujo values
(
flujo(
(select REF(n) from tbl_nodo n where n.codigo='NO 1-11'),
(select REF(n) from tbl_nodo n where n.codigo='NO 1-12'),
graf_cuenca('Negro',1,graf_flujo(arr_puntos(Punto(159,474),
Punto(241,474)),2),null,null,null),
3,null,null,
apor_extrac( 1,
Canal('CA 2','Rama Cipreses',1000,100,1000,0,3000,
arr_caudales(array_caudal(0,0,0,0,0,0)))
,null,null
)
)
)
/
244
Código Fuente
C.3 Pantallas.
C.3.1 Datos de Conexión
C.3.2 Abrir cuenca existente
245
Código Fuente
C.3.3 Ventana Principal, después de abrir una cuenca.
(Frame1.java)
C.3.4 Agregar Cuenca
246
Código Fuente
C.3.5 Ventana simulación al finalizar
C.3.6 Nodos y sus caudales
247
Código Fuente
C.3.7 Modificando un Rio (FrmModificarRio.java y FrmRio.java)
FrmModificarRio.java
FrmRio.java
C.3.8 Acerca de (Frame1_AboutBox.java)
248
Código Fuente
C.3.9 Propiedadas de un Canal (FrmCanal.java)
C.3.10 Propiedades de una Captación de Agua Potable
(FrmCapAguaPot.java)
C.3.11 Propiedades de una central hidroeléctrica
(FrmCentralHidro.java)
249
Código Fuente
C.3.12 Propiedades de una hoya intermedia (frmHoyaInter.java)
C.3.13 Propiedades de un régimen natural (frmRegNat.java)
C.3.14 Propiedades de una salida de embalse
(frmSalidaEmb.java)
250
Código Fuente
C.3.15 Propiedades de un tramo de río (FrmTramo.java)
C.3.16 Propiedades de un nodo (frmNodo.java)
C.3.17 Ventana para la modificación del Zoom (FrmZoom.java)
251
Código Fuente
C.3.18 Menu Cuenca
C.3.19 Menu Río
C.3.20 Menu Zoom
C.3.21 Menu Insertar
252
Código Fuente
C.3.22 Menu Consultas
C.3.23 Menu Ayuda
253
Código Fuente
C.4 Código Java.
C.4.1 Paquete consultorSql
C.4.1.1 Clase: ConectorJDBC
//Nombre del archivo ConectorJDBC.java
package consultorSql;
import java.sql.*;
import Oracle.jdbc.driver.*;
import Oracle.sql.*;
public class ConectorJDBC
{
OracleConnection
connection=null;
String
url;
String
usr;
String
driver;
String
passwd;
public ConectorJDBC()
{
}
public ConectorJDBC(String url, String driverName,String user, String
passwd)
{
this.url
= url;
this.driver = driverName;
this.usr
= user;
this.passwd = passwd;
{
/*----------------------------* Funcion mutadora de Usr
*/
public void setUsr(String usr)
{
this.usr=usr;
}
/**-----------------------------* Funcion mutadora de passwd
*/
public void setPasswd(String passwd)
{
this.passwd = passwd;
}
/**------------------------------* Funcion mutadora de Url
254
Código Fuente
*/
public void setUrl(String url)
{
this.url = url;
}
/**------------------------------* Funcion mutadora de driver
*/
public void setDriver(String driver)
{
this.driver = driver;
}
/**------------------------------* Funcion observadora de Usr
*/
public String getUsr()
{
return this.usr;
}
/**------------------------------* Funcion observadora de passwd
*/
public String getPasswd()
{
return this.passwd;
}
/**------------------------------* Funcion observadora de Url
*/
public String getUrl()
{
return this.url ;
}
/**------------------------------* Funcion observadora de driver
*/
public String getDriver()
{
return this.driver;
}
/**---------------------------------------------------------* Abre la coneccion a la base de datos con los atributos de
255
Código Fuente
* coneccion.
*/
public void open() throws Exception
{
Class.forName(driver);
System.out.println("conectando a la base de datos...");
connection = (OracleConnection)
DriverManager.getConnection(url, usr, passwd);
}
/**---------------------------------------------------------* Abre la coneccion a la base de datos con los atributos de
* coneccion.
*/
public void open(String url, String driverName,
String user, String passwd) throws Exception
{
Class.forName(driverName);
System.out.println("conectando a la base de datos...");
connection =(OracleConnection)
DriverManager.getConnection(url, user, passwd);
}
/**----------------------------------------------------------* Cierra la conneccion a la base de datos.
*/
public void close() throws SQLException
{
System.out.println("Cerrando la conneccion a la base
de datos");
connection.close();
}
public Connection getConnection()
{
return connection;
}
public OracleConnection getOracleConnection()
{
return connection;
}
public boolean isClosed() throws SQLException
{
return ((this.connection==null)
||(connection.isClosed()));
}
public boolean isOpen() throws SQLException
{
256
Código Fuente
}
}
return !((this.connection==null)||
(connection.isClosed()));
C.4.1.2 Clase: FrmConexion
//Nombre del archivo FrmConexion.java
package consultorSql;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class FrmConexion extends JDialog
{
JPanel jPanel1 = new JPanel();
JButton btSalir = new JButton();
JPanel jPanel2 = new JPanel();
GridLayout gridLayout1 = new GridLayout();
JPanel jPanel3 = new JPanel();
JPanel jPanel4 = new JPanel();
JPanel jPanel5 = new JPanel();
JPanel jPanel6 = new JPanel();
JLabel jLabel1 = new JLabel();
JPasswordField paswd = new JPasswordField();
JLabel jLabel2 = new JLabel();
JTextField url = new JTextField();
JLabel jLabel3 = new JLabel();
JTextField driver = new JTextField();
JLabel jLabel4 = new JLabel();
FlowLayout flowLayout1 = new FlowLayout();
FlowLayout flowLayout2 = new FlowLayout();
FlowLayout flowLayout3 = new FlowLayout();
FlowLayout flowLayout4 = new FlowLayout();
JTextField user = new JTextField();
JPanel jPanel7 = new JPanel();
JPanel jPanel8 = new JPanel();
JPanel jPanel9 = new JPanel();
private ConectorJDBC conector;
JButton btConectar = new JButton();
public FrmConexion()
{
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
}
257
Código Fuente
public FrmConexion(Frame po,ConectorJDBC conector)
{
super(po);
try
{
jbInit();
this.conector=conector;
}
catch(Exception e)
{
e.printStackTrace();
}
}
public FrmConexion(Frame po)
{
super(po);
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void jbInit() throws Exception
{
btSalir.setPreferredSize(new Dimension(89, 25));
btSalir.setMinimumSize(new Dimension(89, 25));
btSalir.setText("Salir");
btSalir.setMnemonic('S') ;
btSalir.setMaximumSize(new Dimension(89, 25));
btSalir.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
btSalir_keyReleased(e);
}
});
btSalir.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
btSalir_actionPerformed(e);
}
});
jPanel2.setLayout(gridLayout1);
gridLayout1.setRows(4);
jLabel1.setText("Nombre de Usuario");
jLabel1.setPreferredSize(new Dimension(127, 15));
jLabel1.setMinimumSize(new Dimension(127, 15));
258
Código Fuente
jLabel1.setMaximumSize(new Dimension(127, 15));
paswd.setPreferredSize(new Dimension(215, 19));
paswd.setMinimumSize(new Dimension(215, 19));
paswd.setText("romero");
paswd.setMaximumSize(new Dimension(215, 19));
paswd.addFocusListener(new java.awt.event.FocusAdapter()
{
public void focusGained(FocusEvent e)
{
paswd_focusGained(e);
}
public void focusLost(FocusEvent e)
{
paswd_focusLost(e);
}
});
paswd.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
paswd_keyReleased(e);
}
});
jLabel2.setText("Contraseña");
jLabel2.setPreferredSize(new Dimension(127, 15));
jLabel2.setMinimumSize(new Dimension(127, 15));
jLabel2.setMaximumSize(new Dimension(127, 15));
url.setPreferredSize(new Dimension(215, 19));
url.setMinimumSize(new Dimension(215, 19));
url.setSelectionStart(0);
url.setText("jdbc:Oracle:thin:@zorro:1521:ORCL");
url.setSelectionEnd(0);
url.setMaximumSize(new Dimension(215, 19));
url.addFocusListener(new java.awt.event.FocusAdapter()
{
public void focusGained(FocusEvent e)
{
url_focusGained(e);
}
public void focusLost(FocusEvent e)
{
url_focusLost(e);
}
});
url.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
url_keyReleased(e);
}
});
jLabel3.setText("URL JDBC");
jLabel3.setPreferredSize(new Dimension(127, 15));
jLabel3.setMinimumSize(new Dimension(127, 15));
259
Código Fuente
jLabel3.setMaximumSize(new Dimension(127, 15));
driver.setPreferredSize(new Dimension(215, 19));
driver.setMinimumSize(new Dimension(215, 19));
driver.setText("Oracle.jdbc.driver.OracleDriver");
driver.setMaximumSize(new Dimension(215, 19));
driver.addFocusListener(new java.awt.event.FocusAdapter()
{
public void focusGained(FocusEvent e)
{
driver_focusGained(e);
}
public void focusLost(FocusEvent e)
{
driver_focusLost(e);
}
});
driver.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
driver_keyReleased(e);
}
});
jPanel3.setLayout(flowLayout1);
jPanel4.setLayout(flowLayout2);
jPanel5.setLayout(flowLayout3);
jPanel6.setLayout(flowLayout4);
flowLayout1.setAlignment(FlowLayout.LEFT);
flowLayout2.setAlignment(FlowLayout.LEFT);
flowLayout3.setAlignment(FlowLayout.LEFT);
flowLayout4.setAlignment(FlowLayout.LEFT);
user.setPreferredSize(new Dimension(215, 19));
user.setMinimumSize(new Dimension(215, 19));
user.setText("miguel");
user.setMaximumSize(new Dimension(215, 19));
user.addFocusListener(new java.awt.event.FocusAdapter()
{
public void focusGained(FocusEvent e)
{
user_focusGained(e);
}
public void focusLost(FocusEvent e)
{
user_focusLost(e);
}
});
user.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
user_keyPressed(e);
}
});
jLabel4.setText("Driver JDBC");
260
Código Fuente
}
jLabel4.setPreferredSize(new Dimension(127, 15));
jLabel4.setMinimumSize(new Dimension(127, 15));
jLabel4.setToolTipText("");
jLabel4.setMaximumSize(new Dimension(127, 15));
jPanel2.setBorder(BorderFactory.createEtchedBorder());
this.setModal(true);
this.setTitle("Datos de Conección");
jPanel1.setMinimumSize(new Dimension(10, 10));
btConectar.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
btConectar_actionPerformed(e);
}
});
btConectar.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
btConectar_keyReleased(e);
}
});
btConectar.setText("Conectar");
btConectar.setMnemonic('C');
this.getContentPane().add(jPanel1, BorderLayout.SOUTH);
jPanel1.add(btConectar, null);
jPanel1.add(btSalir, null);
this.getContentPane().add(jPanel2, BorderLayout.CENTER);
jPanel2.add(jPanel3, null);
jPanel3.add(jLabel1, null);
jPanel3.add(user, null);
jPanel2.add(jPanel4, null);
jPanel4.add(jLabel2, null);
jPanel4.add(paswd, null);
jPanel2.add(jPanel5, null);
jPanel5.add(jLabel3, null);
jPanel5.add(url, null);
jPanel2.add(jPanel6, null);
jPanel6.add(jLabel4, null);
jPanel6.add(driver, null);
this.getContentPane().add(jPanel7, BorderLayout.WEST);
this.getContentPane().add(jPanel8, BorderLayout.EAST);
this.getContentPane().add(jPanel9, BorderLayout.NORTH);
void user_keyPressed(KeyEvent e)
{
if (e.getKeyChar()=='\n')
{
paswd.requestFocus();
}
}
void paswd_keyReleased(KeyEvent e)
261
Código Fuente
{
if (e.getKeyChar()=='\n')
{
url.requestFocus();
}
}
void url_keyReleased(KeyEvent e)
{
if (e.getKeyChar()=='\n')
{
driver.requestFocus();
}
}
void driver_keyReleased(KeyEvent e)
{
if (e.getKeyChar()=='\n')
{
btSalir.requestFocus();
}
}
void btSalir_actionPerformed(ActionEvent e)
{
this.hide();
}
void user_focusGained(FocusEvent e)
{
user.setSelectionStart(0) ;
user.setSelectionEnd(user.getText().length()) ;
}
void paswd_focusGained(FocusEvent e)
{
paswd.setSelectionStart(0) ;
paswd.setSelectionEnd(paswd.getPassword().length);
}
void url_focusGained(FocusEvent e)
{
url.setSelectionStart(0) ;
url.setSelectionEnd(url.getText().length()) ;
}
void driver_focusGained(FocusEvent e)
{
driver.setSelectionStart(0) ;
262
Código Fuente
driver.setSelectionEnd(driver.getText().length()) ;
}
void user_focusLost(FocusEvent e)
{
user.setSelectionStart(0) ;
user.setSelectionEnd(0) ;
}
void paswd_focusLost(FocusEvent e)
{
paswd.setSelectionStart(0) ;
paswd.setSelectionEnd(0) ;
}
void url_focusLost(FocusEvent e)
{
url.setSelectionStart(0) ;
url.setSelectionEnd(0) ;
}
void driver_focusLost(FocusEvent e)
{
paswd.setSelectionStart(0) ;
paswd.setSelectionEnd(0) ;
}
/**
* entregan los datos de coneccion
*/
public String getUsr()
{
return user.getText();
}
public String getPasswd()
{
return new String(paswd.getPassword());
}
public String getUrl()
{
return url.getText();
}
public String getDriver()
{
return driver.getText();
}
void btSalir_keyReleased(KeyEvent e)
263
Código Fuente
{
if (e.getKeyChar()=='\n')
{
this.hide();
}
}
void btConectar_actionPerformed(ActionEvent e)
{
try
{
conector.setDriver(this.getDriver());
conector.setUrl(this.getUrl());
conector.setUsr(this.getUsr() );
conector.setPasswd(this.getPasswd());
if(conector.isOpen())
{
conector.close();
conector.open();
}
else
{
conector.open();
}
this.hide();
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this,"Error al conectar: "+ex) ;
}
}
void btConectar_keyTyped(KeyEvent e)
{
}
void btConectar_keyPressed(KeyEvent e)
{
}
void btConectar_keyReleased(KeyEvent e)
{
}
}
//habilita o deshabilita el boton salir
public void enbableBtSalir(boolean enabled)
{
btSalir.setEnabled(enabled);
}
264
Código Fuente
C.4.1.3 Clase: FrmConsultor
package consultorSql;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class FrmConsultor extends JDialog
{
GridBagLayout gridBagLayout3 = new GridBagLayout();
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JTextArea jTextArea1 = new JTextArea();
sqlQuery sqlQuery1 = new sqlQuery();
String usr;
String passwd;
String url;
String driver;
/**
* Constructor
*/
public FrmConsultor()
{
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Construcctor para el FrmConsultor
*/
public FrmConsultor(String usr,String passwd,String url,String driver)
{
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
sqlQuery1.setUsr(usr) ;
sqlQuery1.setPasswd(passwd) ;
sqlQuery1.setUrl(url) ;
sqlQuery1.setDriver(driver) ;
sqlQuery1.setActive(true) ;
265
Código Fuente
}
/**
* Construcctor para el FrmConsultor
*/
public FrmConsultor(Frame po,String usr,String passwd,String url,String
driver)
{
super(po);
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
sqlQuery1.setUsr(usr) ;
sqlQuery1.setPasswd(passwd) ;
sqlQuery1.setUrl(url) ;
sqlQuery1.setDriver(driver) ;
sqlQuery1.setActive(true) ;
}
private void jbInit() throws Exception
{
this.getContentPane().setLayout(gridBagLayout3);
this.setModal(true);
this.setTitle("Consultas SQL");
this.addWindowListener(new java.awt.event.WindowAdapter()
{
public void windowActivated(WindowEvent e)
{
this_windowActivated(e);
}
});
jButton1.setNextFocusableComponent(jButton2);
jButton1.setText("Ejecutar");
jButton1.setMnemonic('E') ;
jButton1.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jButton1_actionPerformed(e);
}
});
jButton2.setNextFocusableComponent(jTextArea1);
jButton2.setText("Salir");
jButton2.setMnemonic('S') ;
jButton2.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
jButton2_keyReleased(e);
}
266
Código Fuente
});
jButton2.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jButton2_actionPerformed(e);
}
});
jTextArea1.setNextFocusableComponent(jButton1);
jTextArea1.setText("Select * from dual");
jTextArea1.setToolTipText("escriba la consulta, para ejecutarla
utilize alt + e o el botón Ejecutar");
sqlQuery1.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
sqlQuery1.setDoubleBuffered(true);
sqlQuery1.setUsr("miguel");
sqlQuery1.setPasswd("romero");
sqlQuery1.setUrl("jdbc:Oracle:thin:@zorro:1521:ORCL");
sqlQuery1.setDriver("Oracle.jdbc.driver.OracleDriver");
sqlQuery1.setQuery("Select * from Dual");
sqlQuery1.setActive(true);
this.getContentPane().add(jScrollPane1, new GridBagConstraints(0, 3,
GridBagConstraints.REMAINDER, 10, 1.0, 0.666666666
,GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(3,
7, 7, 7), 0, 0));
jScrollPane1.getViewport().add(sqlQuery1, null);
this.getContentPane().add(jButton1, new GridBagConstraints(1, 0, 1,
1,0.0,0.0,GridBagConstraints.NORTHEAST,
GridBagConstraints.BOTH, new Insets(7, 3, 3, 7), 0, 0));
this.getContentPane().add(jButton2, new GridBagConstraints(1, 1, 1,
1, 0.0, 0.0,GridBagConstraints.NORTHEAST,
GridBagConstraints.BOTH, new Insets(3, 3, 3, 7), 0, 0));
this.getContentPane().add(jScrollPane2, new GridBagConstraints(0, 0,
1, 3, 0.6, 0.23,GridBagConstraints.NORTHWEST,
GridBagConstraints.BOTH, new Insets(7, 7, 3, 3), 93, 18));
jScrollPane2.getViewport().add(jTextArea1, null);
}
void jButton2_actionPerformed(ActionEvent e)
{
this.hide() ;
}
void jButton2_keyReleased(KeyEvent e)
{
if (e.getKeyChar()=='\n')
{
this.hide();
}
}
void jButton1_actionPerformed(ActionEvent e)
{
267
Código Fuente
ejecutarConsulta();
}
void ejecutarConsulta()
{
String query=jTextArea1.getText().trim() ;
sqlQuery1.setQuery(query) ;
sqlQuery1.exeQuery();
}
}
void this_windowActivated(WindowEvent e)
{
jTextArea1.requestFocus();
}
C.4.1.4 Clase: JDBCAdapter
//Nota: esta clase pertenece a los ejemplos de JDK 1.2,
// pero tiene algunas modificaciones para ser utilizada en este proyecto
package consultorSql;
import
import
import
import
java.util.Vector;
java.sql.*;
javax.swing.table.AbstractTableModel;
javax.swing.event.TableModelEvent;
public class JDBCAdapter extends AbstractTableModel {
Connection
connection;
Statement
statement;
ResultSet
resultSet;
String[]
columnNames = {};
Vector
rows = new Vector();
ResultSetMetaData
metaData;
public JDBCAdapter()
{
}
public JDBCAdapter(String url, String driverName,
String user, String passwd)
{
try{
open(url,driverName,user,passwd);
}
catch (Exception e)
{
System.err.println(e);
}
}
268
Código Fuente
/**
* Ejecuta la consulta pasada por parametro.
*/
public void executeQuery(String query) throws SQLException
{
if (connection == null || statement == null) {
SQLException e=new SQLException("Base de datos
Cerrada");
System.err.println("No hay base de datos que ejecute la
consulta, debe conectarse a una");
throw e;
}
resultSet = statement.executeQuery(query);
metaData = resultSet.getMetaData();
int numberOfColumns = metaData.getColumnCount();
columnNames = new String[numberOfColumns];
// Get the column names and cache them.
// Then we can close the connection.
for(int column = 0; column < numberOfColumns; column++) {
columnNames[column] = metaData.getColumnLabel(column+1);
}
// Get all rows.
rows = new Vector();
while (resultSet.next()) {
Vector newRow = new Vector();
for (int i = 1; i <= getColumnCount(); i++) {
newRow.addElement(resultSet.getObject(i));
}
rows.addElement(newRow);
}
fireTableChanged(null); // Tell the listeners a new table
// has arrived.
}
/**********************************************************************
* Abre la coneccion a la base de datos con los atributos de coneccion.
*/
public void open(String url, String driverName,
String user, String passwd) throws Exception
{
Class.forName(driverName);
System.out.println("conectando a la base de datos...");
connection = DriverManager.getConnection(url, user, passwd);
statement = connection.createStatement();
}
269
Código Fuente
/**
* Cierra la conneccion a la base de datos.
*/
public void close() throws SQLException {
System.out.println("Cerrando la conneccion a la base de datos");
resultSet.close();
statement.close();
connection.close();
}
protected void finalize() throws Throwable {
close();
super.finalize();
}
////////////////////////////////////////////////////////////////////////
//
//
//
Implementacion de la interfaz TableModel
//
////////////////////////////////////////////////////////////////////////
//
// MetaData
public String getColumnName(int column) {
if (columnNames[column] != null) {
return columnNames[column];
} else {
return "";
}
}
public Class getColumnClass(int column) {
int type;
try {
type = metaData.getColumnType(column+1);
}
catch (SQLException e) {
return super.getColumnClass(column);
}
switch(type) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return String.class;
case Types.BIT:
return Boolean.class;
case Types.TINYINT:
270
Código Fuente
case Types.SMALLINT:
case Types.INTEGER:
return Integer.class;
case Types.BIGINT:
return Long.class;
case Types.FLOAT:
case Types.DOUBLE:
return Double.class;
case Types.DATE:
return java.sql.Date.class;
}
default:
return Object.class;
}
public boolean isCellEditable(int row, int column) {
try {
return metaData.isWritable(column+1);
}
catch (SQLException e) {
return false;
}
}
public int getColumnCount() {
return columnNames.length;
}
// Data methods
public int getRowCount() {
return rows.size();
}
public Object getValueAt(int aRow, int aColumn) {
Vector row = (Vector)rows.elementAt(aRow);
return row.elementAt(aColumn);
}
public String dbRepresentation(int column, Object value) {
int type;
if (value == null) {
return "null";
}
try {
type = metaData.getColumnType(column+1);
}
catch (SQLException e) {
271
Código Fuente
}
return value.toString();
switch(type) {
case Types.INTEGER:
case Types.DOUBLE:
case Types.FLOAT:
return value.toString();
case Types.BIT:
return ((Boolean)value).booleanValue() ? "1" : "0";
case Types.DATE:
return value.toString().trim();
default:
return "\""+value.toString()+"\"";
}
}
public void setValueAt(Object value, int row, int column) {
try {
String tableName = metaData.getTableName(column+1);
if (tableName == null) {
System.out.println("Table name returned null.");
}
String columnName = getColumnName(column);
String query =
"update "+tableName+
" set "+columnName+" = "+dbRepresentation(column, value)+
" where ";
// We don't have a model of the schema so we don't know the
// primary keys or which columns to lock on. To demonstrate
// that editing is possible, we'll just lock on everything.
for(int col = 0; col<getColumnCount(); col++) {
String colName = getColumnName(col);
if (colName.equals("")) {
continue;
}
if (col != 0) {
query = query + " and ";
}
query = query + colName +" = "+
dbRepresentation(col, getValueAt(row, col));
}
System.out.println(query);
//System.out.println("Not sending update to database");
// statement.executeQuery(query);
}
catch (SQLException e) {
//
e.printStackTrace();
System.err.println("Update failed");
}
Vector dataRow = (Vector)rows.elementAt(row);
dataRow.setElementAt(value, column);
272
Código Fuente
}
}
C.4.1.5 Clase: OldJTable
//Nota: esta clase pertenece a los ejemplos de JDK 1.2,
// pero tiene algunas modificaciones para ser utilizada en este proyecto
package consultorSql;
import
import
import
import
import
import
import
import
java.lang.Thread;
java.util.*;
java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.event.*;
javax.swing.plaf.*;
javax.swing.table.*;
/**
* The OldJTable is an unsupported class containing some methods that
* were deleted from the JTable between releases 0.6 and 0.7
*/
public class OldJTable extends JTable
{
/*
* A new convenience method returning the index of the column in the
* co-ordinate space of the view.
*/
public int getColumnIndex(Object identifier)
{
return getColumnModel().getColumnIndex(identifier);
}
//
//
//
//
Methods deleted from the JTable because they only work with the
DefaultTableModel.
public TableColumn addColumn(Object columnIdentifier, int width)
{
return addColumn(columnIdentifier, width, null, null, null);
}
public TableColumn addColumn(Object columnIdentifier,
Vector columnData)
{
return addColumn(columnIdentifier, -1, null, null, columnData);
}
public TableColumn addColumn(Object columnIdentifier, int width,
TableCellRenderer renderer,TableCellEditor editor)
273
Código Fuente
{
}
return addColumn(columnIdentifier, width, renderer, editor,
null);
public TableColumn addColumn(Object columnIdentifier, int width,
TableCellRenderer renderer, TableCellEditor
editor, Vector columnData)
{
checkDefaultTableModel();
// Set up the model side first
DefaultTableModel m = (DefaultTableModel)getModel();
m.addColumn(columnIdentifier, columnData);
}
// The column will have been added to the end, so the index of the
// column in the model is the last element.
TableColumn newColumn = new TableColumn(m.getColumnCount()-1,
width, renderer, editor);
super.addColumn(newColumn);
return newColumn;
public void removeColumn(Object columnIdentifier) {
super.removeColumn(getColumn(columnIdentifier));
}
public void addRow(Object[] rowData) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).addRow(rowData);
}
public void addRow(Vector rowData) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).addRow(rowData);
}
public void removeRow(int rowIndex) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).removeRow(rowIndex);
}
public void moveRow(int startIndex, int endIndex, int toIndex)
{
checkDefaultTableModel();
((DefaultTableModel)getModel()).moveRow(startIndex, endIndex,
toIndex);
}
public void insertRow(int rowIndex, Object[] rowData) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).insertRow(rowIndex, rowData);
}
public void insertRow(int rowIndex, Vector rowData) {
274
Código Fuente
}
checkDefaultTableModel();
((DefaultTableModel)getModel()).insertRow(rowIndex, rowData);
public void setNumRows(int newSize) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).setNumRows(newSize);
}
public void setDataVector(Vector newData, Vector columnIds) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).setDataVector(newData, columnIds);
}
public void setDataVector(Object[][] newData, Object[] columnIds) {
checkDefaultTableModel();
((DefaultTableModel)getModel()).setDataVector(newData, columnIds);
}
protected void checkDefaultTableModel() {
if(!(dataModel instanceof DefaultTableModel))
throw new InternalError("In order to use this method, the
data model must be an instance of efaultTableModel.");
}
//
//
//
Methods removed from JTable in the move from identifiers to ints.
public Object getValueAt(Object columnIdentifier, int rowIndex) {
return super.getValueAt(rowIndex,
getColumnIndex(columnIdentifier));
}
public boolean isCellEditable(Object columnIdentifier, int rowIndex)
{
return super.isCellEditable(rowIndex,
getColumnIndex(columnIdentifier));
}
public void setValueAt(Object aValue, Object columnIdentifier,
int rowIndex)
{
super.setValueAt(aValue,
rowIndex,getColumnIndex(columnIdentifier));
}
public boolean editColumnRow(Object identifier, int row) {
return super.editCellAt(row, getColumnIndex(identifier));
}
public void moveColumn(Object columnIdentifier,
Object targetColumnIdentifier)
275
Código Fuente
{
}
moveColumn(getColumnIndex(columnIdentifier),
getColumnIndex(targetColumnIdentifier));
public boolean isColumnSelected(Object identifier) {
return isColumnSelected(getColumnIndex(identifier));
}
public TableColumn addColumn(int modelColumn, int width) {
return addColumn(modelColumn, width, null, null);
}
public TableColumn addColumn(int modelColumn) {
return addColumn(modelColumn, 75, null, null);
}
/**
* Creates a new column with <I>modelColumn</I>, <I>width</I>,
* <I>renderer</I>, and <I>editor</I> and adds it to the end of
* the JTable's array of columns. This method also retrieves the
* name of the column using the model's <I>
* getColumnName(modelColumn) </I> method, and sets the both the
* header value and the identifier for this TableColumn accordingly.
* <p>
* The <I>modelColumn</I> is the index of the column in the model
* which will supply the data for this column in the table. This,
* like the <I>columnIdentifier</I> in previous releases, does not
* change as the columns are moved in the view.
* <p>
* For the rest of the JTable API, and all of its associated
* classes, columns are referred to in the co-ordinate system of the
* view, the index of the column in the model is kept inside the
* TableColumn and is used only to retrieve the information from the
* appropraite column in the model.
* <p>
*
* @param
modelColumn The index of the column in the model
* @param
width
The new column's width. Or -1 to use
*
the default width
* @param
renderer
The renderer used with the new column.
*
Or null to use the default renderer.
* @param
editor
The editor used with the new column.
*
Or null to use the default editor.
*/
public TableColumn addColumn(int modelColumn, int width,
TableCellRenderer renderer,
TableCellEditor editor)
{
TableColumn newColumn = new TableColumn(modelColumn, width,
renderer, editor);
addColumn(newColumn);
return newColumn;
276
Código Fuente
}
public boolean editColumnRow(int columnIndex, int rowIndex) {
return super.editCellAt(rowIndex, columnIndex);
}
public boolean editColumnRow(int columnIndex, int rowIndex,
EventObject e)
{
return super.editCellAt(rowIndex, columnIndex, e);
}
}
// End Of Class OldJTable
C.4.1.6 Clase sqlQuery
//Nota: esta clase pertenece a los ejemplos de JDK 1.2,
// pero tiene algunas modificaciones para ser utilizada en este proyecto
package consultorSql;
import java.sql.SQLException;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import java.awt.event.*;
import javax.swing.JWindow;
public class sqlQuery extends JTable
{
private TableSorter sorter=new TableSorter();
private JDBCAdapter dataBase=new JDBCAdapter();
private String usr="";
private String passwd="";
private String url="";
private String driver="";
private String query="";
private boolean active=false;
/**
* Constructor por derfecto del sqlQuery
*/
public sqlQuery()
{
this.setModel(sorter);
sorter.addMouseListenerToHeaderInTable(this);
sorter.setModel(dataBase) ;
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
277
Código Fuente
}
/**
* Funcion mutadora de Usr
*/
public void setUsr(String usr)
{
this.usr=usr;
}
/**
* Funcion mutadora de passwd
*/
public void setPasswd(String passwd)
{
this.passwd = passwd;
}
/**
* Funcion mutadora de Url
*/
public void setUrl(String url)
{
this.url = url;
}
/**
* Funcion mutadora de driver
*/
public void setDriver(String driver)
{
this.driver = driver;
}
/**
* Funcion mutadora de query
*/
public void setQuery(String query)
{
this.query = query;
}
/**
* Funcion mutadora de active
*/
public void setActive(boolean active)
{
if (active)
{
if ((url!="") && (driver!="") && ( usr !="") && (passwd !="") &&
(query!=""))
{
try {
dataBase.open(url,driver,usr,passwd);
278
Código Fuente
dataBase.executeQuery(query) ;
sorter.setModel(dataBase);
}
catch (Exception e)
{
System.err.println(e);
active=false;
}
}
else active=false;
}
else
{
}
try
{
dataBase.close() ;
}
catch (Exception e) {
System.err.println("base de datos no se pudo cerrar");
System.err.println(e);
active=false;
}
}
this.active = active;
/**
* Funcion observadora de Usr
*/
public String getUsr()
{
return this.usr;
}
/**
* Funcion observadora de passwd
*/
public String getPasswd()
{
return this.passwd;
}
/**
* Funcion observadora de Url
*/
public String getUrl()
{
return this.url ;
}
/**
* Funcion observadora de driver
*/
279
Código Fuente
public String getDriver()
{
return this.driver;
}
/**
* Funcion observadora de active
*/
public boolean getActive()
{
return this.active;
}
/**
* Funcion observadora de query
*/
public String getQuery()
{
return this.query;
}
/**
* Funcion que ejecuta la consulta del atributo query
*/
public void exeQuery()
{
if (!this.active) {this.setActive(true);}
try
{
dataBase.executeQuery(query);
}
catch (SQLException e){
JOptionPane.showMessageDialog(this,e.getMessage()) ;
}
}
private void jbInit() throws Exception
{
this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
this.addFocusListener(new java.awt.event.FocusAdapter()
{
public void focusGained(FocusEvent e)
{
this_focusGained(e);
}
});
}
void this_focusGained(FocusEvent e)
{
}
280
Código Fuente
}
C.4.1.7 Clase: TableMap
//Nota: esta clase pertenece a los ejemplos de JDK 1.2,
// pero tiene algunas modificaciones para ser utilizada en este proyecto
package consultorSql;
import javax.swing.table.*;
import javax.swing.event.TableModelListener;
import javax.swing.event.TableModelEvent;
public class TableMap extends AbstractTableModel implements
TableModelListener
{
protected TableModel model;
public TableModel
return model;
}
getModel() {
public void setModel(TableModel model) {
this.model = model;
model.addTableModelListener(this);
}
// By default, Implement TableModel by forwarding all messages
// to the model.
public Object getValueAt(int aRow, int aColumn) {
return model.getValueAt(aRow, aColumn);
}
public void setValueAt(Object aValue, int aRow, int aColumn) {
model.setValueAt(aValue, aRow, aColumn);
}
public int getRowCount() {
return (model == null) ? 0 : model.getRowCount();
}
public int getColumnCount() {
return (model == null) ? 0 : model.getColumnCount();
}
public String getColumnName(int aColumn) {
return model.getColumnName(aColumn);
}
public Class getColumnClass(int aColumn) {
return model.getColumnClass(aColumn);
}
public boolean isCellEditable(int row, int column) {
return model.isCellEditable(row, column);
281
Código Fuente
}
//
// Implementation of the TableModelListener interface,
// By default forward all events to all the listeners.
public void tableChanged(TableModelEvent e) {
fireTableChanged(e);
}
}
C.4.1.8 Clase: TableSorter
//Nota: esta clase pertenece a los ejemplos de JDK 1.2,
// pero tiene algunas modificaciones para ser utilizada en este proyecto
package consultorSql;
import java.util.*;
import javax.swing.table.TableModel;
import javax.swing.event.TableModelEvent;
// Imports for picking up mouse events from the JTable.
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class TableSorter extends TableMap
{
int
indexes[];
Vector
sortingColumns = new Vector();
boolean
ascending = true;
int compares;
public TableSorter()
{
indexes = new int[0]; // For consistency.
}
public TableSorter(TableModel model)
{
setModel(model);
}
public void setModel(TableModel model) {
super.setModel(model);
reallocateIndexes();
}
public int compareRowsByColumn(int row1, int row2, int column)
{
282
Código Fuente
Class type = model.getColumnClass(column);
TableModel data = model;
// Check for nulls
Object o1 = data.getValueAt(row1, column);
Object o2 = data.getValueAt(row2, column);
// If both values are null return 0
if (o1 == null && o2 == null) {
return 0;
}
else if (o1 == null) { // Define null less than everything.
return -1;
}
else if (o2 == null) {
return 1;
}
/* We copy all returned values from the getValue call in case
an optimised model is reusing one object to return many values.
The Number subclasses in the JDK are immutable and so will not
be used in this way but other subclasses of Number might want
to do this to save space and avoid unnecessary heap allocation.
*/
if (type.getSuperclass() == java.lang.Number.class)
{
Number n1 = (Number)data.getValueAt(row1, column);
double d1 = n1.doubleValue();
Number n2 = (Number)data.getValueAt(row2, column);
double d2 = n2.doubleValue();
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
else
return 0;
}
else if (type
{
Date d1
long n1
Date d2
long n2
== java.util.Date.class)
=
=
=
=
(Date)data.getValueAt(row1, column);
d1.getTime();
(Date)data.getValueAt(row2, column);
d2.getTime();
if (n1 < n2)
return -1;
else if (n1 > n2)
return 1;
else return 0;
}
else if (type == String.class)
{
283
Código Fuente
String s1 = (String)data.getValueAt(row1, column);
String s2
= (String)data.getValueAt(row2, column);
int result = s1.compareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else return 0;
}
else if (type
{
Boolean
boolean
Boolean
boolean
}
else
{
}
}
== Boolean.class)
bool1 = (Boolean)data.getValueAt(row1, column);
b1 = bool1.booleanValue();
bool2 = (Boolean)data.getValueAt(row2, column);
b2 = bool2.booleanValue();
if (b1 == b2)
return 0;
else if (b1) // Define false < true
return 1;
else
return -1;
Object v1 = data.getValueAt(row1, column);
String s1 = v1.toString();
Object v2 = data.getValueAt(row2, column);
String s2 = v2.toString();
int result = s1.compareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else return 0;
public int compare(int row1, int row2)
{
compares++;
for(int level = 0; level < sortingColumns.size(); level++)
{
Integer column = (Integer)sortingColumns.elementAt(level);
int result = compareRowsByColumn(row1, row2,
column.intValue());
if (result != 0) return ascending ? result : -result;
}
return 0;
}
public void
reallocateIndexes()
284
Código Fuente
{
int rowCount = model.getRowCount();
// Set up a new array of indexes with the right number of elements
// for the new data model.
indexes = new int[rowCount];
}
// Initialise with the identity mapping.
for(int row = 0; row < rowCount; row++)
indexes[row] = row;
public void tableChanged(TableModelEvent e)
{
System.out.println("Sorter: tableChanged");
reallocateIndexes();
}
super.tableChanged(e);
public void checkModel()
{
if (indexes.length != model.getRowCount()) {
System.err.println("Sorter not informed of a change in
model.");
}
}
public void sort(Object sender)
{
checkModel();
compares = 0;
// n2sort();
// qsort(0, indexes.length-1);
//similar a mergesort;
shuttlesort((int[])indexes.clone(), indexes, 0, indexes.length);
System.out.println("Compares: "+compares);
}
public void n2sort() {
for(int i = 0; i < getRowCount(); i++) {
for(int j = i+1; j < getRowCount(); j++) {
if (compare(indexes[i], indexes[j]) == -1) {
swap(i, j);
}
}
}
}
//
//
//
//
//
This is a home-grown implementation which we have not had time
to research - it may perform poorly in some circumstances. It
requires twice the space of an in-place algorithm and makes
NlogN assigments shuttling the values between the two
arrays. The number of compares appears to vary between N-1 and
285
Código Fuente
// NlogN depending on the initial order but the main reason for
// using it here is that, unlike qsort, it is stable.
public void shuttlesort(int from[], int to[], int low, int high) {
if (high - low < 2) {
return;
}
int middle = (low + high)/2;
shuttlesort(to, from, low, middle);
shuttlesort(to, from, middle, high);
int p = low;
int q = middle;
/* This is an optional short-cut; at each recursive call,
check to see if the elements in this subset are already
ordered. If so, no further comparisons are needed; the
sub-array can just be copied. The array must be copied rather
than assigned otherwise sister calls in the recursion might
get out of sinc. When the number of elements is three they
are partitioned so that the first set, [low, mid), has one
element and and the second, [mid, high), has two. We skip the
optimisation when the number of elements is three or less as
the first compare in the normal merge will produce the same
sequence of steps. This optimisation seems to be worthwhile
for partially ordered lists but some analysis is needed to
find out how the performance drops to Nlog(N) as the initial
order diminishes - it may drop very quickly.
*/
if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0)
{
for (int i = low; i < high; i++) {
to[i] = from[i];
}
return;
}
}
// A normal merge.
for(int i = low; i < high; i++) {
if (q >= high || (p < middle && compare(from[p], from[q]) <=
0))
{
to[i] = from[p++];
}
else
{
to[i] = from[q++];
}
}
public void swap(int i, int j) {
int tmp = indexes[i];
286
Código Fuente
}
indexes[i] = indexes[j];
indexes[j] = tmp;
// The mapping only affects the contents of the data rows.
// Pass all requests to these rows through the mapping array:
// "indexes".
public Object getValueAt(int aRow, int aColumn)
{
checkModel();
return model.getValueAt(indexes[aRow], aColumn);
}
public void setValueAt(Object aValue, int aRow, int aColumn)
{
checkModel();
model.setValueAt(aValue, indexes[aRow], aColumn);
}
public void sortByColumn(int column) {
sortByColumn(column, true);
}
public void sortByColumn(int column, boolean ascending) {
this.ascending = ascending;
sortingColumns.removeAllElements();
sortingColumns.addElement(new Integer(column));
sort(this);
super.tableChanged(new TableModelEvent(this));
}
// There is no-where else to put this.
// Add a mouse listener to the Table to trigger a table sort
// when a column heading is clicked in the JTable.
public void addMouseListenerToHeaderInTable(JTable table)
{
final TableSorter sorter = this;
final JTable tableView = table;
tableView.setColumnSelectionAllowed(false);
MouseAdapter listMouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
TableColumnModel columnModel = tableView.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(e.getX());
int column =tableView.convertColumnIndexToModel(viewColumn);
if(e.getClickCount() == 1 && column != -1) {
System.out.println("Sorting ...");
int shiftPressed=e.getModifiers()&InputEvent.SHIFT_MASK;
boolean ascending = (shiftPressed == 0);
sorter.sortByColumn(column, ascending);
}
}
};
JTableHeader th = tableView.getTableHeader();
287
Código Fuente
}
}
th.addMouseListener(listMouseListener);
288
Código Fuente
C.4.2 Paquete cuencamaule
En esta sección mostraremos algunas clases, puesto que la mayoría son 100%
generadas por el RAD JBUILDER 4, a partir del diseño visual de las ventanas.
C.4.2.1 Clase: Frame1
package cuencamaule;
import
import
import
import
import
import
import
import
import
java.awt.*;
java.awt.event.*;
javax.swing.*;
figuras.*;
consultorSql.*;
objcuenca.*;
java.util.*;
javax.swing.border.*;
java.sql.Connection;
public class Frame1 extends JFrame {
boolean insert=false;
int tipoInsert=0;
private static final int INSERT_CANAL=1;
private static final int INSERT_CAP_AGUA_POT=2;
private Graficable figInsert;
private int countClick=0;
private ArrPuntosOra puntos;
JPanel contentPane;
CuencaOraRef CuencaActualRef;
BDObjCuenca dataBase=new BDObjCuenca();
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenuFile = new JMenu();
JMenuItem jMenuFileExit = new JMenuItem();
JMenu jMenuHelp = new JMenu();
JMenuItem jMenuHelpAbout = new JMenuItem();
JToolBar jToolBar = new JToolBar();
JButton btAbrir = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
ImageIcon image1;
ImageIcon image2;
ImageIcon image3;
JLabel statusBar = new JLabel();
BorderLayout borderLayout1 = new BorderLayout();
JScrollPane FigurasSP = new JScrollPane();
JMenuItem menuAbrirCuenca = new JMenuItem();
JMenu jMenu1 = new JMenu();
JMenuItem mnuNodo = new JMenuItem();
JMenuItem menuNueva = new JMenuItem();
JMenuItem mnuEm = new JMenuItem();
JMenuItem mnuHI = new JMenuItem();
289
Código Fuente
JMenuItem mnRN = new JMenuItem();
JMenuItem mnuTr = new JMenuItem();
JMenuItem mnuCAP = new JMenuItem();
JMenuItem mnuCanal = new JMenuItem();
JMenuItem mnuCentHidro = new JMenuItem();
JMenuItem menuModificarCuenca = new JMenuItem();
JMenu jMenu2 = new JMenu();
JRadioButtonMenuItem jRadioButtonMenuItem2 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem3 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem4 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem5 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem7 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem8 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem9 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem10 = new
JRadioButtonMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem6 = new
JRadioButtonMenuItem();
JMenu jMenu3 = new JMenu();
JMenuItem mnuEmbBajos = new JMenuItem();
JMenuItem mnuEnGen = new JMenuItem();
JRadioButtonMenuItem jRadioButtonMenuItem11 = new
JRadioButtonMenuItem();
JMenuItem jMenuSimular = new JMenuItem();
JMenuItem jMenuItem17 = new JMenuItem();
JMenuItem jMenuItem2 = new JMenuItem();
JMenuItem jMenuItem18 = new JMenuItem();
JMenuItem jMenuItem19 = new JMenuItem();
FrmConexion datosConeccion;
LienzoCuenca lienzo = new LienzoCuenca();
JPanel jPanel1 = new JPanel();
JPanel jPanel3 = new JPanel();
Border border1;
JPanel jPanel4 = new JPanel();
GridBagLayout gridBagLayout2 = new GridBagLayout();
JLabel jlMensaje = new JLabel();
JPanel jPanel5 = new JPanel();
GridBagLayout gridBagLayout1 = new GridBagLayout();
JLabel jlPunto = new JLabel();
JPanel jPanel2 = new JPanel();
JMenu jMenu4 = new JMenu();
JMenuItem menuNuevoRio = new JMenuItem();
JMenuItem menuModificarRio = new JMenuItem();
/**Construct the frame*/
public Frame1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
290
Código Fuente
jbInit();
}
}
catch(Exception e) {
e.printStackTrace();
}
/**Component initialization*/
private void jbInit() throws Exception {
image1 = new
ImageIcon(cuencamaule.Frame1.class.getResource("openFile.gif"));
image2 = new
ImageIcon(cuencamaule.Frame1.class.getResource("closeFile.gif"));
image3 = new
ImageIcon(cuencamaule.Frame1.class.getResource("help.gif"));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(647, 452));
this.addWindowListener(new java.awt.event.WindowAdapter()
{
public void windowOpened(WindowEvent e)
{
this_windowOpened(e);
}
});
this.setTitle("Modelo de Simulación Hidrologico Operacional");
statusBar.setText(" ");
jMenuFile.setText("Cuenca");
jMenuFile.setMnemonic('C');
jMenuFileExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(88,
java.awt.event.KeyEvent.CTRL_MASK, true));
jMenuFileExit.setText("Salir");
jMenuFileExit.setMnemonic('S');
jMenuFileExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jMenuFileExit_actionPerformed(e);
}
});
jMenuHelp.setText("Ayuda");
jMenuHelp.setMnemonic('A');
jMenuHelpAbout.setText("Acerca de...");
jMenuHelpAbout.setMnemonic('c');
jMenuHelpAbout.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jMenuHelpAbout_actionPerformed(e);
}
});
btAbrir.setIcon(image1);
btAbrir.setToolTipText("Open File");
btAbrir.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
291
Código Fuente
btAbrir_actionPerformed(e);
}
});
jButton2.setIcon(image2);
jButton2.setToolTipText("Simular");
jButton3.setIcon(image3);
jButton3.setToolTipText("Ayuda");
FigurasSP.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
FigurasSP.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
FigurasSP.getViewport().setBackground(Color.white);
menuAbrirCuenca.setText("Abrir...");
menuAbrirCuenca.setMnemonic('A');
menuAbrirCuenca.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuAbrirCuenca_actionPerformed(e);
}
});
jMenu1.setText("Insertar");
jMenu1.setMnemonic('I');
mnuNodo.setEnabled(false);
mnuNodo.setText("Nodo");
mnuNodo.setMnemonic('N');
mnuNodo.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuNodo_actionPerformed(e);
}
});
menuNueva.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78,
java.awt.event.KeyEvent.CTRL_MASK, true));
menuNueva.setText("Nueva...");
menuNueva.setMnemonic('N');
menuNueva.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuNueva_actionPerformed(e);
}
});
mnuEm.setEnabled(false);
mnuEm.setText("Embalse");
mnuEm.setMnemonic('E');
mnuEm.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuEm_actionPerformed(e);
292
Código Fuente
}
});
mnuHI.setEnabled(false);
mnuHI.setText("Hoya Intermedia");
mnuHI.setMnemonic('H');
mnuHI.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuHI_actionPerformed(e);
}
});
mnRN.setEnabled(false);
mnRN.setText("Regimen Natural");
mnRN.setMnemonic('g');
mnRN.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnRN_actionPerformed(e);
}
});
mnuTr.setEnabled(false);
mnuTr.setText("Tramo");
mnuTr.setMnemonic('T');
mnuTr.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuTr_actionPerformed(e);
}
});
mnuCAP.setEnabled(false);
mnuCAP.setText("Captación Agua Potable");
mnuCAP.setMnemonic('C');
mnuCAP.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuCAP_actionPerformed(e);
}
});
mnuCanal.setEnabled(false);
mnuCanal.setText("Canal");
mnuCanal.setMnemonic('a');
mnuCanal.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuCanal_actionPerformed(e);
}
});
mnuCentHidro.setEnabled(false);
mnuCentHidro.setText("Central Hidroeléctrica");
293
Código Fuente
mnuCentHidro.setMnemonic('l');
mnuCentHidro.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuCentHidro_actionPerformed(e);
}
});
menuModificarCuenca.setEnabled(false);
menuModificarCuenca.setText("Modificar...");
menuModificarCuenca.setMnemonic(77);
menuModificarCuenca.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuModificarCuenca_actionPerformed(e);
}
});
jMenu2.setText("Zoom");
jMenu2.setMnemonic('Z');
jRadioButtonMenuItem2.setEnabled(false);
jRadioButtonMenuItem2.setText("15%");
jRadioButtonMenuItem2.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jRadioButtonMenuItem2_actionPerformed(e);
}
});
jRadioButtonMenuItem3.setEnabled(false);
jRadioButtonMenuItem3.setText("30%");
jRadioButtonMenuItem3.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jRadioButtonMenuItem3_actionPerformed(e);
}
});
jRadioButtonMenuItem4.setEnabled(false);
jRadioButtonMenuItem4.setText("50%");
jRadioButtonMenuItem4.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem4_actionPerformed(e);
}
});
jRadioButtonMenuItem5.setEnabled(false);
jRadioButtonMenuItem5.setText("75%");
jRadioButtonMenuItem5.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
294
Código Fuente
jRadioButtonMenuItem5_actionPerformed(e);
}
});
jRadioButtonMenuItem7.setEnabled(false);
jRadioButtonMenuItem7.setText("125%");
jRadioButtonMenuItem7.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem7_actionPerformed(e);
}
});
jRadioButtonMenuItem8.setEnabled(false);
jRadioButtonMenuItem8.setText("150%");
jRadioButtonMenuItem8.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem8_actionPerformed(e);
}
});
jRadioButtonMenuItem9.setEnabled(false);
jRadioButtonMenuItem9.setText("200%");
jRadioButtonMenuItem9.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem9_actionPerformed(e);
}
});
jRadioButtonMenuItem10.setEnabled(false);
jRadioButtonMenuItem10.setText("300%");
jRadioButtonMenuItem10.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem10_actionPerformed(e);
}
});
jRadioButtonMenuItem6.setEnabled(false);
jRadioButtonMenuItem6.setSelected(true);
jRadioButtonMenuItem6.setText("100%");
jRadioButtonMenuItem6.addActionListener(new
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jRadioButtonMenuItem6_actionPerformed(e);
}
});
jMenu3.setText("Consultas");
jMenu3.setMnemonic('o');
mnuEmbBajos.setEnabled(false);
mnuEmbBajos.setText("Embalse Bajo sus Volumens Minimos...");
mnuEmbBajos.setMnemonic('E');
mnuEmbBajos.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
295
Código Fuente
mnuEmbBajos_actionPerformed(e);
}
});
mnuEnGen.setEnabled(false);
mnuEnGen.setText("Energía Generada...");
mnuEnGen.setMnemonic('n');
mnuEnGen.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mnuEnGen_actionPerformed(e);
}
});
ButtonGroup group = new ButtonGroup();
jRadioButtonMenuItem11.setEnabled(false);
jRadioButtonMenuItem11.setText("Personalizado...");
jRadioButtonMenuItem11.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jRadioButtonMenuItem11_actionPerformed(e);
}
});
jMenuSimular.setEnabled(false);
jMenuSimular.setText("Iniciar Simulación...");
jMenuSimular.setMnemonic(73);
jMenuSimular.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jMenuSimular_actionPerformed(e);
}
});
jMenuItem17.setText("Conección...");
jMenuItem17.setMnemonic('o');
jMenuItem17.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jMenuItem17_actionPerformed(e);
}
});
jMenuItem2.setText("SQL...");
jMenuItem2.setMnemonic('S');
jMenuItem2.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jMenuItem2_actionPerformed(e);
}
});
jMenuItem18.setText("Contenido...");
296
Código Fuente
jMenuItem18.setMnemonic('C');
jMenuItem19.setText("Búsqueda...");
jMenuItem19.setMnemonic('B');
jPanel4.setLayout(gridBagLayout2);
jPanel3.setLayout(gridBagLayout1);
jMenu4.setText("Rio");
jMenu4.setMnemonic(82);
menuNuevoRio.setText("Nuevo...");
menuNuevoRio.setMnemonic(78);
menuNuevoRio.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuNuevoRio_actionPerformed(e);
}
});
menuModificarRio.setText("Modificar...");
menuModificarRio.setMnemonic(77);
menuModificarRio.addActionListener(new
java.awt.event.ActionListener()
{
public void actionPerformed(ActionEvent e)
{
menuModificarRio_actionPerformed(e);
}
});
lienzo.setBackground(Color.white);
lienzo.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
lienzo_mouseClicked(e);
}
});
group.add(jRadioButtonMenuItem2);
group.add(jRadioButtonMenuItem3);
group.add(jRadioButtonMenuItem4);
group.add(jRadioButtonMenuItem5);
group.add(jRadioButtonMenuItem6);
group.add(jRadioButtonMenuItem7);
group.add(jRadioButtonMenuItem8);
group.add(jRadioButtonMenuItem9);
group.add(jRadioButtonMenuItem10);
group.add(jRadioButtonMenuItem11);
jMenuFile.add(menuNueva);
jMenuFile.add(menuAbrirCuenca);
jMenuFile.add(menuModificarCuenca);
jMenuFile.addSeparator();
jMenuFile.add(jMenuItem17);
jMenuFile.add(jMenuSimular);
jMenuFile.addSeparator();
jMenuFile.add(jMenuFileExit);
297
Código Fuente
}
jMenuHelp.add(jMenuItem18);
jMenuHelp.add(jMenuItem19);
jMenuHelp.add(jMenuHelpAbout);
jMenuBar1.add(jMenuFile);
jMenuBar1.add(jMenu4);
jMenuBar1.add(jMenu2);
jMenuBar1.add(jMenu1);
jMenuBar1.add(jMenu3);
jMenuBar1.add(jMenuHelp);
this.setJMenuBar(jMenuBar1);
contentPane.add(FigurasSP, BorderLayout.CENTER);
FigurasSP.getViewport().add(lienzo, null);
contentPane.add(jToolBar, BorderLayout.NORTH);
jToolBar.add(btAbrir);
jToolBar.add(jButton2);
jToolBar.add(jButton3, null);
contentPane.add(jPanel3, BorderLayout.SOUTH);
jPanel3.add(jlMensaje, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
,GridBagConstraints.WEST, GridBagConstraints.BOTH, new
Insets(0, 12, 4, 8), 0, 0));
jPanel3.add(jlPunto, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new
Insets(4, 12, 4, 12), 0, 0));
contentPane.add(jPanel5, BorderLayout.EAST);
contentPane.add(jPanel2, BorderLayout.WEST);
jMenu1.add(mnuNodo);
jMenu1.add(mnuTr);
jMenu1.add(mnuEm);
jMenu1.add(mnuHI);
jMenu1.add(mnRN);
jMenu1.add(mnuCAP);
jMenu1.add(mnuCanal);
jMenu1.add(mnuCentHidro);
jMenu2.add(jRadioButtonMenuItem2);
jMenu2.add(jRadioButtonMenuItem3);
jMenu2.add(jRadioButtonMenuItem4);
jMenu2.add(jRadioButtonMenuItem5);
jMenu2.add(jRadioButtonMenuItem6);
jMenu2.add(jRadioButtonMenuItem7);
jMenu2.add(jRadioButtonMenuItem8);
jMenu2.add(jRadioButtonMenuItem9);
jMenu2.add(jRadioButtonMenuItem10);
jMenu2.add(jRadioButtonMenuItem11);
jMenu3.add(mnuEmbBajos);
jMenu3.add(mnuEnGen);
jMenu3.add(jMenuItem2);
jMenu4.add(menuNuevoRio);
jMenu4.add(menuModificarRio);
public void jMenuFileExit_actionPerformed(ActionEvent e) {
System.exit(0);
}
298
Código Fuente
public void jMenuHelpAbout_actionPerformed(ActionEvent e) {
Frame1_AboutBox dlg = new Frame1_AboutBox(this);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.setModal(true);
dlg.show();
}
/**Overridden so we can exit when window is closed*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
jMenuFileExit_actionPerformed(null);
}
}
void jRadioButtonMenuItem1_actionPerformed(ActionEvent e)
{
lienzo.setZoom(5);
}
void jRadioButtonMenuItem2_actionPerformed(ActionEvent e)
{
lienzo.setZoom(15);
}
void jRadioButtonMenuItem3_actionPerformed(ActionEvent e)
{
lienzo.setZoom(30);
}
void jRadioButtonMenuItem4_actionPerformed(ActionEvent e) {
lienzo.setZoom(50);
}
void jRadioButtonMenuItem5_actionPerformed(ActionEvent e) {
lienzo.setZoom(75);
}
void jRadioButtonMenuItem6_actionPerformed(ActionEvent e) {
lienzo.setZoom(100);
}
void jRadioButtonMenuItem7_actionPerformed(ActionEvent e) {
lienzo.setZoom(125);
}
void jRadioButtonMenuItem8_actionPerformed(ActionEvent e) {
lienzo.setZoom(150);
}
299
Código Fuente
void jRadioButtonMenuItem9_actionPerformed(ActionEvent e) {
lienzo.setZoom(200);
}
void jRadioButtonMenuItem10_actionPerformed(ActionEvent e) {
lienzo.setZoom(300);
}
void jRadioButtonMenuItem11_actionPerformed(ActionEvent e)
{
//llamar al dialogo de zoom
FrmZoom dlg = new FrmZoom(this, lienzo);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.show();
}
void menuNueva_actionPerformed(ActionEvent e)
{
try
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
try{dataBase.open() ;}
catch(Exception err)
{
JOptionPane.showMessageDialog(this,err.getMessage());
err.printStackTrace(System.err) ;
}
}
FrmCuenca dlg=new FrmCuenca(this.dataBase,null);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack();
dlg.show();
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this, "Error al conectar a la base
de datos "+ex.getMessage()) ;
}
300
Código Fuente
}
void abrirCuenca()
{
try
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
dataBase.open() ;
}
FRMAbrirCuenca dlg = new FRMAbrirCuenca(this,dataBase);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack();
dlg.show();
}
catch(Exception err)
{
JOptionPane.showMessageDialog(this,err.getMessage());
err.printStackTrace(System.err) ;
}
}
/**
* Abre una cuenca.
*/
void menuAbrirCuenca_actionPerformed(ActionEvent e)
{
jlMensaje.setText("Abriendo la cuenca...");
abrirCuenca();
jlMensaje.setText(" ");
}
void menuModificarCuenca_actionPerformed(ActionEvent e)
{
try
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
try{dataBase.open() ;}
catch(Exception err)
{
301
Código Fuente
JOptionPane.showMessageDialog(this,err.getMessage());
err.printStackTrace(System.err) ;
}
}
if (CuencaActualRef==null)
{
JOptionPane.showMessageDialog(this,"Debe Abrir una cuenca
Primero") ;
}
else
{
FrmCuenca dlg=new
FrmCuenca(this.dataBase,this.CuencaActualRef);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack();
dlg.show();
}
}
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this, "Error al conectar a la base
de datos "+ex.getMessage()) ;
}
finally
{
if(FrmCuenca.accionRealizada==FrmCuenca.ELIMINAR)
{
setEnabledMenu(false);
this.setTitle("Modelo de Simulacion Hidrologico operacional");
this.CuencaActualRef=null;
}
}
/**
* pone en enable o disable todos los itemes del zoom
*/
private void setEnabledMenu(boolean enabled)
{
jRadioButtonMenuItem2.setEnabled(enabled);
jRadioButtonMenuItem3.setEnabled(enabled);
jRadioButtonMenuItem4.setEnabled(enabled);
jRadioButtonMenuItem5.setEnabled(enabled);
jRadioButtonMenuItem6.setEnabled(enabled);
jRadioButtonMenuItem7.setEnabled(enabled);
jRadioButtonMenuItem8.setEnabled(enabled);
jRadioButtonMenuItem9.setEnabled(enabled);
jRadioButtonMenuItem10.setEnabled(enabled);
jRadioButtonMenuItem11.setEnabled(enabled);
302
Código Fuente
this.menuModificarCuenca.setEnabled(enabled);
this.jMenuSimular.setEnabled(enabled);
this.mnRN.setEnabled(enabled);
this.mnuCanal.setEnabled(enabled);
this.mnuCAP.setEnabled(enabled);
this.mnuCAP.setEnabled(enabled);
this.mnuNodo.setEnabled(enabled);
this.mnuCentHidro .setEnabled(enabled);
this.mnuTr.setEnabled(enabled);
this.mnuEm.setEnabled(enabled);
this.mnuHI.setEnabled(enabled);
this.mnuEmbBajos.setEnabled(enabled);
this.mnuEnGen.setEnabled(enabled);
}
/****************************************************************
*
* Llama al dialogo de conección.
*
*/
void jMenuItem17_actionPerformed(ActionEvent e)
{
Dimension dlgSize = datosConeccion.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
datosConeccion.setLocation((frmSize.width - dlgSize.width) / 2 +
loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
datosConeccion.pack() ;
datosConeccion.show();
}
/************************************************************
* Realiza la simulación.
*/
void jMenuSimular_actionPerformed(ActionEvent e)
{
try
{
if(this.CuencaActualRef !=null)
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
dataBase.open();
}
FRMSimular dlg=new FRMSimular(this,dataBase);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
303
Código Fuente
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack() ;
dlg.show() ;
}
else
{JOptionPane.showMessageDialog(this,"La cuenca está cerrada,
ábrala nuevamente");
}
}
}
catch (Exception err)
{
JOptionPane.showMessageDialog(this,err.getMessage());
err.printStackTrace(System.err) ;
}
/**********************************************************
*
*/
void mnuNodo_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void jMenuItem6_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnuTr_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnuEm_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnuHI_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnRN_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnuCAP_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
304
Código Fuente
}
void mnuCanal_actionPerformed(ActionEvent e)
{
this.insert=true;
this.tipoInsert=INSERT_CANAL;
this.setEnabledMenu(false);
}
void mnuCentHidro_actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(this,"Por Implementar... ");
}
void mnuEmbBajos_actionPerformed(ActionEvent e)
{
try
{
frmResultConsulta frm=new frmResultConsulta();
frm.sqlQuery1.setUrl(this.dataBase.getUrl());
frm.sqlQuery1.setDriver(this.dataBase.getDriver());
frm.sqlQuery1.setUsr(this.dataBase.getUsr());
frm.sqlQuery1.setPasswd(this.dataBase.getPasswd());
frm.setTituloInforme("Embalses Bajo volumenes mínimos");
frm.sqlQuery1.setQuery(
"Select "+
"emb.codigo\"CODIGO\""+
" from tbl_emb emb"+
" Where emb.myNodo.myCuenca.codigo=\'" +
this.getCuencaRef().getValue().getCodigo()+ "\'"+ "and "+
"
(
emb.curva_Alerta.getCaudal(1)>emb.caudales.getCaudal(1)"+
"
Or emb.curva_Alerta.getCaudal(2)>emb.caudales.getCaudal(2)"+
"
Or emb.curva_Alerta.getCaudal(3)>emb.caudales.getCaudal(3)"+
"
Or emb.curva_Alerta.getCaudal(4)>emb.caudales.getCaudal(4)"+
"
Or emb.curva_Alerta.getCaudal(5)>emb.caudales.getCaudal(5)"+
"
Or emb.curva_Alerta.getCaudal(6)>emb.caudales.getCaudal(6)"+
"
) "
);
frm.pack();
frm.setLocation((int)(this.getLocation().getX()20),(int)(this.getLocation().getY()-10));
frm.show();
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this,"error en FrmSimular: "+
ex.getMessage()) ;
}
}
void mnuEnGen_actionPerformed(ActionEvent e)
{
try
305
Código Fuente
{
frmResultConsulta frm=new frmResultConsulta();
frm.sqlQuery1.setUrl(this.dataBase.getUrl());
frm.sqlQuery1.setDriver(this.dataBase.getDriver());
frm.sqlQuery1.setUsr(this.dataBase.getUsr());
frm.sqlQuery1.setPasswd(this.dataBase.getPasswd());
frm.setTituloInforme("Energia Generada en KW mes");
frm.sqlQuery1.setQuery(
"Select "+
"n.apex.ch.codigo\"CODIGO\","+
"n.apex.ch.nombre\"NOMBRE\","+
" to_char(n.apex.ch.KW(1), \'999,999,999.99\') " + "\"OCT\","+
" to_char(n.apex.ch.KW(2), \'999,999,999.99\') " + "\"NOV\","+
" to_char(n.apex.ch.KW(3), \'999,999,999.99\') " + "\"DIC\","+
" to_char(n.apex.ch.KW(4), \'999,999,999.99\') " + "\"ENE\","+
" to_char(n.apex.ch.KW(5), \'999,999,999.99\') " + "\"FEB\","+
" to_char(n.apex.ch.KW(6), \'999,999,999.99\') " + "\"MAR\""+
" from tbl_flujo n"+
" Where n.apex.tipo=3 and "+
"
(
n.nodo_ini.myCuenca.codigo=\'" +
this.getCuencaRef().getValue().getCodigo() + "\'" +
"
Or n.nodo_fin.myCuenca.codigo=\'" +
this.getCuencaRef().getValue().getCodigo() + "\'" +
"
) "
);
frm.pack();
frm.setLocation((int)(this.getLocation().getX()20),(int)(this.getLocation().getY()-10));
frm.show();
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this,"error en FrmSimular: "+
ex.getMessage()) ;
}
}
void jMenuItem2_actionPerformed(ActionEvent e)
{
String usr=datosConeccion.getUsr();
String passwd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String driver=datosConeccion.getDriver();
FrmConsultor dlg = new FrmConsultor(this,usr,passwd,url,driver);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack() ;
dlg.show();
}
306
Código Fuente
public void setCuencaRef(CuencaOraRef cr)
{
try
{
jlMensaje.setText("Obteniendo Figuras...");
CuencaActualRef=cr;
lienzo.clearFiguras();
Vector figuras=dataBase.getAllFigRef(cr.getValue());
jlMensaje.setText("Cargando Figuras...");
lienzo.setVectorFiguras(figuras);
jlMensaje.setText(" ") ;
this.setTitle("Cuenca Actual :
"+this.CuencaActualRef.getValue().getCodigo()+"-"+
this.CuencaActualRef.getValue().getNombre());
this.setEnabledMenu(true);
}
catch (Exception err)
{
JOptionPane.showMessageDialog(this,"En setCuencaRef()
:"+err.getMessage());
err.printStackTrace(System.err) ;
}
}
public CuencaOraRef getCuencaRef()
{
return CuencaActualRef;
}
void btAbrir_actionPerformed(ActionEvent e)
{
abrirCuenca();
}
void this_mouseMoved(MouseEvent e)
{
jlPunto.setText("(" + e.getX() + "," + e.getY() +")") ;
}
void FigurasSP_mouseMoved(MouseEvent e)
{
jlPunto.setText("(" + e.getX() + "," + e.getY() +")") ;
}
void lienzo_mouseMoved(MouseEvent e)
{
jlPunto.setText("(" + e.getX() + "," + e.getY() +")") ;
}
/**********************************************************************
*
*/
void menuNuevoRio_actionPerformed(ActionEvent e)
{
307
Código Fuente
try
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
dataBase.open() ;
}
FrmRio dlg=new FrmRio(this.dataBase,null);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack();
dlg.show();
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this, "Error al conectar a la base
de datos "+ex.getMessage()) ;
}
}
/***********************************************************************
*
*/
void menuModificarRio_actionPerformed(ActionEvent e)
{
try
{
if ((dataBase==null)||(dataBase.isClosed()))
{
String usr=datosConeccion.getUsr();
String psswd=datosConeccion.getPasswd();
String url=datosConeccion.getUrl();
String drv=datosConeccion.getDriver();
dataBase=new BDObjCuenca(url,drv,usr,psswd);
dataBase.open() ;
}
FrmModificarRio dlg=new FrmModificarRio(this,dataBase);
Dimension dlgSize = dlg.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
(frmSize.height - dlgSize.height) / 2 + loc.y);
dlg.pack();
dlg.show();
}
catch (Exception ex)
{
308
Código Fuente
}
}
JOptionPane.showMessageDialog(this, "Error al conectar a la
base de datos : "+ex.getMessage()) ;
/**
* Crea un canal con valores por defectos
*/
private FlujoOra crearCanal(Graficable noIni,Graficable noFin)
{
try
{
FlujoOra flujo=new
FlujoOra(this.dataBase.getConnection());
flujo.setNodoIni((NodoOraRef)noIni);
flujo.setNodoFin((NodoOraRef)noFin);
flujo.setTipo(new java.math.BigDecimal(3));
//actualizadondo el atributo graf
GrafCuencaOra gc=new
GrafCuencaOra(dataBase.getConnection());
GrafFlujoOra gf=new
GrafFlujoOra(dataBase.getConnection());
gf.setEstilo(new java.math.BigDecimal(2));
//este punto se ingresa para que el arreglos
//de puntos no sea null
//pero el valor sera corregido mas adelante.
this.puntos=new ArrPuntosOra(new PuntoOra[1]);
PuntoOra p = new
PuntoOra(dataBase.getConnection());
p.setX(new java.math.BigDecimal(0));
p.setY(new java.math.BigDecimal(0));
this.puntos.setElement(p,0);
gf.setPl(this.puntos);
gc.setColorlinea("negro") ;
gc.setTipo(new java.math.BigDecimal(1));
gc.setGfl(gf);
flujo.setGraf(gc);
//actualizando el tipo apex
AporExtracOra apex=new
AporExtracOra(this.dataBase.getConnection());
apex.setTipo(new java.math.BigDecimal(1));
CanalOra ca=new
CanalOra(dataBase.getConnection());
ca.setA(new java.math.BigDecimal(0));
ca.setB(new java.math.BigDecimal(0));
ca.setC(new java.math.BigDecimal(0));
ca.setCodigo("CA nuevo");
ca.setNombre("Canal en proceso de ingreso");
ca.setCapConducion(new
java.math.BigDecimal(0));
ca.setEficiencia(new java.math.BigDecimal(0));
ArrCaudalesOra arrCaudales=new
ArrCaudalesOra(dataBase.getConnection());
ArrayCaudalOra arr=new ArrayCaudalOra(new
309
Código Fuente
java.math.BigDecimal[6]);
arr.setElement(new java.math.BigDecimal(0),0);
arr.setElement(new java.math.BigDecimal(0),1);
arr.setElement(new java.math.BigDecimal(0),2);
arr.setElement(new java.math.BigDecimal(0),3);
arr.setElement(new java.math.BigDecimal(0),4);
arr.setElement(new java.math.BigDecimal(0),5);
arrCaudales.setCaudal(arr);
ca.setCaudales(arrCaudales) ;
apex.setCa(ca);
flujo.setApex(apex);
return flujo;
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,"eror al crear canal por
defecto : "+ex);
}
return null;
}
//********************************************************************
//
void lienzo_mouseClicked(MouseEvent e)
{
try
{
boolean esNodo=false;
if (this.insert)
{
if (this.tipoInsert==this.INSERT_CANAL)
{
Graficable f=lienzo.buscarFigura(e.getX(),e.getY()) ;
try
{esNodo=(f.getClass().getName()=="objcuenca.GuiNodo");}
catch (Exception ex)
{esNodo=false;}
//si es el primer punto, debe ser un nodo.
if(this.countClick ==0)
{
if(esNodo)
{
FlujoOra flujo=this.crearCanal(f,f);
this.figInsert=(Graficable)dataBase.insertar(flujo);
this.countClick++;
}
else
{
JOptionPane.showMessageDialog(this,"El Primer
punto del canal debe ser del nodo inicial");
}
}
else
310
Código Fuente
{
GuiFlujo flref=(GuiFlujo)this.figInsert;
FlujoOra flujo=flref.getValue();
if(esNodo)
{
if(this.countClick > 2)
{
//actualizo el nodo final
//this.jlMensaje.setText("Nodo Final marcado");
flujo.setNodoFin((NodoOraRef)f);
this.countClick=0;
this.insert=false;
this.tipoInsert=0;
flref.setValue(flujo);
flref.loadFigura();
this.figInsert=(Graficable)flref;
this.figInsert.dlgAtributos();
this.setEnabledMenu(true);
this.jlMensaje.setText(" ");
}
else
{
JOptionPane.showMessageDialog(this,"Minimo se
necesitan dos puntos(sin contar nodo inicial y
final)");
}
}
else
{
GrafCuencaOra gc=flujo.getGraf();;
GrafFlujoOra gf=flujo.getGraf().getGfl();;
PuntoOra p = new PuntoOra(dataBase.getConnection());
int x=(e.getX()*100)/lienzo.getZoom();
int y=(e.getY()*100)/lienzo.getZoom();
p.setX(new java.math.BigDecimal(x));
p.setY(new java.math.BigDecimal(y));
//extiendo el arreglo, asignandole uno nuevo.
PuntoOra[] arrPuntos=new PuntoOra[countClick];
// traslado los valores originales para
// que no se pierdan
for(int i=0;i<countClick-1;i++)
{
arrPuntos[i]=this.puntos.getElement(i);
}
arrPuntos[countClick-1]=p;
this.puntos.setArray(arrPuntos);
gf.setPl(this.puntos);
gc.setGfl(gf);
flujo.setGraf(gc);
countClick++;
flref.setValue(flujo);
flref.loadFigura();
this.figInsert=(Graficable)flref;
311
Código Fuente
}
}
if(countClick==3){this.lienzo.addFigura(figInsert);}
if(countClick>2)
{
this.figInsert.dibujar(new
Dibujante(lienzo.getGraphics(),lienzo.getZoom()));
}
}
}
else
{
lienzo.Click(e);
}
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(this,"Error al insertar el
canal:"+ex);
ex.printStackTrace(System.err);
}
}
void this_windowOpened(WindowEvent e)
{
//llamar al dialogo de conección,
try
{
datosConeccion=new FrmConexion(this,dataBase);
Dimension dlgSize = datosConeccion.getPreferredSize();
Dimension frmSize = getSize();
Point loc = getLocation();
datosConeccion.setLocation((frmSize.width - dlgSize.width) / 2 +
loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
datosConeccion.enbableBtSalir(false);
datosConeccion.pack() ;
datosConeccion.show();
}
finally
{
datosConeccion.enbableBtSalir(true);
}
}
/******************************************************/
}
312
Código Fuente
C.4.2.20 Clase: MainGui
package cuencamaule;
import javax.swing.UIManager;
import java.awt.*;
public class MainGui {
boolean packFrame = false;
/**Construct the application*/
public MainGui()
{
Frame1 frame = new Frame1();
// Validate frames that have preset sizes
// Pack frames that have useful preferred size info, e.g. from their
// layout
if (packFrame) {
frame.pack();
}
else {
frame.validate();
}
//Center the window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2,
(screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
}
/**Main method*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
new MainGui();
}
313
Código Fuente
C.4.3 Paquete Figuras
C.4.3.1 Clase: Cuadrilatero
package figuras;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Cuadrilatero extends FigGeo
{
private Punto a,b,c,d;
//----------------------------------------------public Cuadrilatero(Punto A,Punto B,Punto C,Punto D)
{ super();a=A;b=B; c=C; d=D;}
//--------------------------------------------------------//Redefiniendo los métodos de FigGeo
public void dibujar(Graphics g)
{
int x[]={a.x,b.x,c.x,d.x};
int y[]={a.y,b.y,c.y,d.y};
g.drawPolygon(x,y,4);
}
//-------------------------------------------------------------public boolean pertenece(Punto p)
{
Punto inicio,fin,direccion;
int coorx,cnt=0,np=4;
Punto q[]={a,b,c,d};
for(int i=0;i<np;i++)
{
inicio=p.restar(q[i%np]);
fin=p.restar(q[(i+1)%np]);
if((inicio.y * fin.y) <=0)
{
if((inicio.y!=0) || (fin.y!=0))
{
direccion = inicio.restar(fin);
coorx = (inicio.x * direccion.y inicio.y * direccion.x);
if(direccion.y<0) coorx*=-1;
if(coorx==0) {cnt =1; break;}
if(coorx > 0)
{
cnt++;
if((inicio.y < 0 && fin.y==0)||
(inicio.y==0 && fin.y<0))
cnt --;
}
}
314
Código Fuente
}
}
return ((cnt %2)!=0);
}//fin función
//------------------------------------------------------------public void dlgAtributos()
{
JOptionPane.showMessageDialog(null,"soy un cuadrilatero");
}
//------------------------------------------------------------public void setZoom(int z)
{ //modificando los atributos a,b,c,d
int actual=getZoom();
a.x=(a.x * z)/actual;
a.y=(a.y * z)/actual;
b.x=(b.x * z)/actual;
b.y=(b.y * z)/actual;
c.x=(c.x * z)/actual;
c.y=(c.y * z)/actual;
d.x=(d.x * z)/actual;
d.y=(d.y * z)/actual;
super.setZoom(z);
}
//---------------------------------------------------------//coordenada x mas lejana al origen
public int xMayor()
{
int mayor=a.x>b.x?a.x:b.x;
mayor=mayor>c.x?mayor:c.x;
mayor=mayor>d.x?mayor:d.x;
return mayor;
}
//-------------------------------------------------------------//coordenada y mas lejana al origen
public int yMayor()
{
int mayor=a.y>b.y?a.y:b.y;
mayor=mayor>c.y?mayor:c.y;
mayor=mayor>d.y?mayor:d.y;
return mayor;
}
//-------------------------------------------------------
}
public String toString()
{
return "{"+a+b+c+d+"}";
}
315
Código Fuente
C.4.3.2 Clase: Dibujante
package figuras;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import objcuenca.*;
import java.sql.SQLException;
import javax.swing.JOptionPane;
import java.math.*;
import java.awt.Color;
public class Dibujante
{
private Graphics g;
private int zoom=100;
private Color colorLinea=Color.black;
public Dibujante(Graphics g,int zoom)
{
this.g=g;
this.zoom=zoom;
}
public void setColorLinea(Color c)
{
this.colorLinea=c;
}
/**
* Dibuja una polilinea a partir de una PolilineaOra
*/
public void drawPolilinea(PolilineaOra p)
{
try
{
g.setColor(colorLinea);
int nPuntos=p.getNpuntos().intValue() ;
int xCor[]=new int[nPuntos];
int yCor[]=new int[nPuntos];
for(int i=0;i<nPuntos;i++)
{
xCor[i]=p.getLospuntos().getElement(i).getX().intValue();
yCor[i]=p.getLospuntos().getElement(i).getY().intValue();
}
g.drawPolyline(xCor,yCor,nPuntos);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
/**
* Dibuja una polilinea a partir de un ArrPuntosOra
*/
316
Código Fuente
public void drawPolilinea(ArrPuntosOra p)
{
try
{
g.setColor(colorLinea);
int nPuntos=p.length();
int xCor[]=new int[nPuntos];
int yCor[]=new int[nPuntos];
for(int i=0;i<nPuntos;i++)
{
xCor[i]=p.getElement(i).getX().intValue();
yCor[i]=p.getElement(i).getY().intValue();
}
g.drawPolyline(xCor,yCor,nPuntos);
int H=xCor[nPuntos-1];
int K=yCor[nPuntos-1];
int X=xCor[nPuntos-2];
int Y=yCor[nPuntos-2];
//el radio es 10 cuando el zoom es 100, por regla de tres simple
//r=10*zoom/100 al simplificar queda r=zoom/10;
int R=this.zoom/10;
int anch=40;
double angulo;
if((X-H)==0)
{ angulo=270;}
else
{ angulo = Math.toDegrees(Math.atan2((Y-K),(X-H)));}
if ((angulo==0)&&(X<H)){angulo=180;}
//ancho de la flecha en grados.
// los grados en fillArc se incrementan en sentido contrario que en
// el plano cartesiano, por esa razón ajusto el ángulo
// inicial con 360-angulo
this.g.fillArc(H-R,K-R,R*2,R*2,(int)(360-angulo-(anch/2)),anch);
}
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
/*************************************************************
* Dibuja una polilinea doble
*/
public void drawPolilineaDoble(PolilineaOra p)
{
try
{
drawPolilineaDoble(p.getLospuntos() );
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
317
Código Fuente
}
err.printStackTrace(System.err) ;
}
/*************************************************************
* Dibuja una polilinea doble a partir de un ArrPuntosOra
*/
public void drawPolilineaDoble(ArrPuntosOra p)
{
try
{
g.setColor(colorLinea);
int nPuntos=p.length();
int xCor[]=new int[nPuntos];
int yCor[]=new int[nPuntos];
for(int i=0;i<nPuntos;i++)
{
xCor[i]=p.getElement(i).getX().intValue();
yCor[i]=p.getElement(i).getY().intValue();
}
g.drawPolyline(xCor,yCor,nPuntos);
int H=xCor[nPuntos-1];
int K=yCor[nPuntos-1];
int X=xCor[nPuntos-2];
int Y=yCor[nPuntos-2];
//el radio es 10 cuando el zoom es 100, por regla de tres simple
//r=10*zoom/100 al simplificar queda r=zoom/10;
int R=this.zoom/10;
int anch=40;
double angulo;
if((X-H)==0)
{ angulo=270;}
else
{ angulo = Math.toDegrees(Math.atan2((Y-K),(X-H)));}
if ((angulo==0)&&(X<H)){angulo=180;}
// los grados en fillArc se incrementan en sentido contrario
// que en el plano cartesiano, por esa razón ajusto el ángulo
// inicial con 360-angulo
this.g.fillArc(H-R,K-R,R*2,R*2,(int)(360-angulo-(anch/2)),anch);
//El radio de la circunferencia rellena del inicio es de 3 al 100%
R=(3*zoom)/100;
this.g.fillArc(xCor[0]-R,yCor[0]-R,R*2,R*2,0,360);
}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
/**
* Dibuja una polilinea Gruesa
318
Código Fuente
*/
public void drawPolilineaGruesa(PolilineaOra p)
{
try
{
this.drawPolilinea(p.getLospuntos());
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
/**
* Dibuja una polilinea Gruesa a partir de un ArrPuntosOra
*/
public void drawPolilineaGruesa(ArrPuntosOra p)
{
this.drawPolilinea(p) ;
}
public void drawCuadrado(CuadradoOra cuad)
{
try
{
g.setColor(colorLinea);
PuntoOra a=cuad.getA() ;
PuntoOra b=cuad.getB() ;
PuntoOra c=cuad.getC() ;
PuntoOra d=cuad.getD() ;
int nPuntos=4;
int xCor[]={a.getX().intValue() ,b.getX().intValue(),
d.getX().intValue(), c.getX().intValue()};
int yCor[]={a.getY().intValue() ,b.getY().intValue(),
d.getY().intValue(), c.getY().intValue()};
g.drawPolygon(xCor,yCor,nPuntos);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
public void drawTriangulo(TrianguloOra t)
{
try
{
g.setColor(colorLinea);
PuntoOra a=t.getA() ;
PuntoOra b=t.getB() ;
PuntoOra c=t.getC() ;
int nPuntos=3;
int xCor[]={a.getX().intValue(),b.getX().intValue(),
c.getX().intValue()};
319
Código Fuente
int yCor[]={a.getY().intValue(),b.getY().intValue(),
c.getY().intValue()};
g.drawPolygon(xCor,yCor,nPuntos);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
public void drawElipse(ElipseOra e)
{
try
{
g.setColor(colorLinea);
PuntoOra cent = e.getCentro() ;
int alto
= e.getAlto().intValue();
int ancho
= e.getAncho().intValue();
int esqIzX
= cent.getX().intValue()- (ancho/2);
int esqIzY
= cent.getY().intValue()- (alto/2);
g.drawOval(esqIzX,esqIzY,ancho,alto);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
public void drawString(String s,int x,int y,int tam)
{
g.setColor(colorLinea);
Font f=new Font("Helvetica",Font.BOLD,tam);
g.setFont(f);
g.drawString(s,x,y);
}
public void drawCenteredString(String s,int x, int y, int w,int h,
int tam)
{
g.setColor(colorLinea);
Font f=new Font("Helvetica",Font.BOLD,tam);
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
int xx = x + (w -fm.stringWidth(s))/2;
int yy = y +(fm.getAscent() + (h -(fm.getAscent()+
fm.getDescent()))/2);
g.drawString(s,xx,yy);
}
}
320
Código Fuente
C.4.3.3 Clase: Elipse
package figuras;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Elipse extends FigGeo
{
private Punto esqIz;
private int ancho,alto;
//---------------------------------------------------public Elipse(Punto c,int an,int al)
{
super();esqIz=c; ancho=an; alto = al;
}
//---------------------------------------------------//Redefiniendo los métodos de FigGeo
public void dibujar(Graphics g)
{
g.drawOval(esqIz.x,esqIz.y,ancho,alto);
}
//--------------------------------------------------------public boolean pertenece(Punto p)
{
Punto c=new Punto(esqIz.x+ancho/2,esqIz.y+alto/2);
int an=ancho/2;
int al=alto/2;
if ((((Math.pow((p.x-c.x),2))/(Math.pow(an,2)))+
((Math.pow((p.y-c.y),2))/(Math.pow(al,2))))<=1)
{return true;}
else
{return false;}
}//fin función
//-----------------------------------------------------------public void dlgAtributos()
{
JOptionPane.showMessageDialog(null,"soy una Elipse");
}
public String toString()
{
return "{"+esqIz+","+ancho+","+alto+"}";
}
//------------------------------------------------------------------//Esta funcion acutaliza las propiedades de la elipse para que
321
Código Fuente
//esten acordes al nuevo Zoom aplicando la regla de 3 simple
public void setZoom(int z)
{ //modificando los atributos esqIz,alto,ancho
int actual=getZoom();
esqIz.x=(esqIz.x * z)/actual;
esqIz.y=(esqIz.y * z)/actual;
ancho=(ancho * z)/actual;
alto =(alto * z)/actual;
super.setZoom(z);
}
//------------------------------------------------------------//coordenada x mas lejana al origen
public int xMayor()
{
return esqIz.x+ancho;
}
//----------------------------------------------------------//coordenada y mas lejana al origen
public int yMayor()
{
return esqIz.y+alto
;
}
}
322
Código Fuente
C.4.3.4 Clase: FigGeo
package figuras;
import java.awt.*;
import javax.swing.*;
import java.awt.Dimension;
abstract class FigGeo
{
private int zoom;
public FigGeo(){zoom=100;}
public abstract void dibujar(Graphics g);
public abstract boolean pertenece(Punto p);
public abstract void dlgAtributos();
public abstract int xMayor();
public abstract int yMayor();
//------------------------------------------------------------public void setZoom(int z)
{
zoom=z;
}
//------------------------------------------------------------public int getZoom()
{
return zoom;
}
//------------------------------------------------------------public boolean esContenidoEn(Dimension d,Dimension nueva)
{
int xM=xMayor()+12;//12 pixeles de margen derecho
int yM=yMayor()+12;//12 pixeles de margen inferir
nueva.width=d.width>xM?d.width:xM;
nueva.height=d.height>yM?d.height:yM;
}
return ((d.width>xM)&(d.height>yM));
}
C.4.3.5 Interfaz: Graficable
package figuras;
import java.awt.Dimension;
public interface Graficable
{
public void
setZoom(int zoom);
public int
getZoom();
public void
dibujar(Dibujante d);
public void
dlgAtributos();
public Dimension dimensionMinima();
public boolean
pertenece(Punto p);
public void loadFigura();
}
323
Código Fuente
C.4.3.6 Clase: LienzoCuenca
package figuras;
import
import
import
import
import
import
import
javax.swing.JPanel;
java.awt.*;
javax.swing.*;
javax.swing.event.*;
javax.swing.border.*;
java.awt.event.MouseEvent;
java.util.*;
public class LienzoCuenca extends JPanel
{
//----------------------------------------------------------------// Variables de Instancia
private Vector
lasFiguras;
private int
zoom=100;
public LienzoCuenca()
{
lasFiguras= new Vector();
setBackground(new Color(255,231,184));
this.setOpaque(false);
//this.addMouseListener( new MouseInputAdapter(){
//
public void mouseClicked(MouseEvent e){ Click(e);}});
}
//--------------------------------------------------------------public void paint(Graphics g)
{
// g.setColor(new Color(15,23,100));
dibujarFiguras(g);
}
//---------------------------------------------------------------public void Click(MouseEvent e)
{
try
{
if ((e.getClickCount() == 1)&&(!e.isConsumed()))
{
int
x = e.getX();
int
y = e.getY();
Graficable f = buscarFigura(x,y);
if (f!=null)
{
f.dlgAtributos();
}
e.consume();
}
}
finally
{
this.repaint();
324
Código Fuente
}
}
public void setVectorFiguras(Vector f)
{
lasFiguras=f;
setZoom(100);
}
//--------------------------------------------------------------------public void clearFiguras()
{
lasFiguras.clear() ;
}
//-------------------------------------------------------------------public void addFigura(Graficable f)
{
lasFiguras.addElement(f);
}
//-------------------------------------------------------------------/**
*
debuelve la referencia de la figura a la cual le pertenece el punto
*
dado por las coordenadas x,y.
*
en caso de existir ninguna, debuelve null.
*/
public Graficable buscarFigura(int x,int y)
{
Graficable f=null;boolean ok=false;
Enumeration FigIter=lasFiguras.elements();
while((FigIter.hasMoreElements())&&(!ok))
{
f=(Graficable)FigIter.nextElement();
if (f.pertenece(new Punto(x,y))){ok=true;}
}
if ( ok )
{return f;}
else
{return null;}
}
//-------------------------------------------------------------------/**
* Dibuja las figuras contenidas en el vector lasFiguras
*
*
*/
public void dibujarFiguras(Graphics g)
{
Dibujante pincel=new Dibujante(g,this.zoom);
Graficable f;
Enumeration FigIter=lasFiguras.elements();
while (FigIter.hasMoreElements())
{
f=(Graficable)FigIter.nextElement();
//Redimiensiono el lienzo si la figura no es contenida
325
Código Fuente
Dimension df=f.dimensionMinima() ;
Dimension dAct=this.getSize() ;
int x=df.width>dAct.width ? df.width : dAct.width ;
int y=df.height > dAct.height ? df.height : dAct.height;
Dimension nueva=new Dimension(x,y);
if ((df.width>dAct.width)||(df.height > dAct.height))
{this.setSize(nueva);}
f.dibujar(pincel) ;
}
}
//--------------------------------------------------------------------public void reloadFiguras()
{
Enumeration figIter=lasFiguras.elements();
Graficable f;
while(figIter.hasMoreElements())
{
f=(Graficable)figIter.nextElement();
f.loadFigura();
}
this.repaint();
}
//-------------------------------------------------------------------public void setZoom(int z)
{
zoom=z;
Graficable f;
Enumeration FigIter=lasFiguras.elements();
while (FigIter.hasMoreElements())
{
f=(Graficable)FigIter.nextElement();
f.setZoom(zoom);
}
this.setSize(1024,768);
repaint(new Rectangle(getSize()));
}
//-----------------------------------------------------------------public int getZoom()
{
return zoom;
}
}
326
Código Fuente
C.4.3.7 Clase: Poligono
package figuras;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Poligono extends FigGeo
{
private int x[];
private int y[];
private int nPuntos=0;
//----------------------------------------------public Poligono(int xP[],int yP[],int n)
{ super();
x=(int[])xP.clone();
y=(int[])yP.clone();
nPuntos=n;
}
//--------------------------------------------------------//Redefiniendo los métodos de FigGeo
public void dibujar(Graphics g)
{
g.drawPolygon(x,y,nPuntos);
}
//------------------------------------------------------------------private Punto[] arrPuntos()
{
Punto arr[]=new Punto[nPuntos];
for (int i=0;i<nPuntos;i++)
{
arr[i]=new Punto(x[i],y[i]);
}
return arr;
}
public boolean pertenece(Punto p)
{
Punto inicio,fin,direccion;
int coorx,cnt=0,np=nPuntos;
Punto q[]=arrPuntos();
for(int i=0;i<np;i++)
{
inicio=p.restar(q[i%np]);
fin=p.restar(q[(i+1)%np]);
if((inicio.y * fin.y) <=0)
{
if((inicio.y!=0) || (fin.y!=0))
{
direccion = inicio.restar(fin);
coorx = (inicio.x * direccion.y 327
Código Fuente
}
}
inicio.y * direccion.x);
if(direccion.y<0) coorx*=-1;
if(coorx==0) {cnt =1; break;}
if(coorx > 0)
{
cnt++;
if((inicio.y < 0 && fin.y==0)||
(inicio.y==0 && fin.y<0))
cnt --;
}
}
return ((cnt %2)!=0);
}//fin función
//--------------------------------------------------------------public void dlgAtributos()
{
JOptionPane.showMessageDialog(null,"soy un Poligono");
}
//--------------------------------------------------------------public void setZoom(int z)
{ //modificando los atributos a,b,c,d
int actual=getZoom();
for(int i=0;i<nPuntos;i++)
{
x[i]=(x[i] * z)/actual;
y[i]=(y[i] * z)/actual;
}
super.setZoom(z);
}
//--------------------------------------------------------------//coordenada x mas lejana al origen
public int xMayor()
{
int mayor=x[0];
for(int i=0;i<nPuntos;i++)
{
mayor=x[i]>mayor?x[i]:mayor;
}
return mayor;
}
//--------------------------------------------------------------//coordenada y mas lejana al origen
public int yMayor()
{
int mayor=y[0];
for(int i=0;i<nPuntos;i++)
{
mayor=y[i]>mayor?y[i]:mayor;
328
Código Fuente
}
return mayor;
}
}
//------------------------------------------------------------public String toString()
{
String s="{";
for(int i=0;i<nPuntos;i++)
{
s+=new Punto(x[i],y[i])+",";
}
s=s.substring(0,s.length()-1)+"}";
return s;
}
C.4.3.8 Clase: PoliLinea
package figuras;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class PoliLinea extends FigGeo
{
private int nPuntos;
private int[] xCor;
private int[] yCor;
private int estilo;
public static final int SIMPLE=1;
public static final int DOBLE =2;
public static final int GRUESA=0;
private int error=250;
//Constructores
//--------------------------------------------------------public PoliLinea(PoliLinea p,int e)
{
super();
estilo=e;
this.nPuntos=p.nPuntos;
xCor=new int[nPuntos];
yCor=new int[nPuntos];
for(int i=0;i<nPuntos;i++)
{
xCor[i]=p.xCor[i];
yCor[i]=p.yCor[i];
329
Código Fuente
}
}
public PoliLinea(int[] x,int[] y,int nPuntos,int e)
{
super();
estilo=e;
this.nPuntos=nPuntos;
xCor=new int[nPuntos];
yCor=new int[nPuntos];
for(int i=0;i<nPuntos;i++)
{
xCor[i]=x[i];
yCor[i]=y[i];
}
}
//--------------------------------------------------------//mueve la polilínea sumando o restando x e y a las
//cordenadas correspondientes
public void moverEn(int x,int y)
{
for(int i=0;i<nPuntos;i++)
{
xCor[i]+=x;
yCor[i]+=y;
}
}
//--------------------------------------------------------//Redefiniendo los métodos de FigGeo
public void dibujar(Graphics g)
{
PoliLinea n1=new PoliLinea(this,SIMPLE);
PoliLinea n2=new PoliLinea(this,SIMPLE);
{
switch(estilo)
case
case
case
SIMPLE:
g.drawPolyline(xCor,yCor,nPuntos);
error=250;
break;
DOBLE:
n1.moverEn(2,0);
n2.moverEn(-2,0);
g.drawPolyline(n1.xCor,n1.yCor,nPuntos);
g.drawPolyline(n2.xCor,n2.yCor,nPuntos);
error=500;
break;
GRUESA:
n1.moverEn(1,0);
g.drawPolyline(n1.xCor,n1.yCor,nPuntos);
330
Código Fuente
}
}
g.drawPolyline(xCor,yCor,nPuntos);
error=300;
break;
g.drawPolyline(n1.xCor,n1.yCor,nPuntos);
g.drawPolyline(n2.xCor,n2.yCor,nPuntos);
/**-----------------------------------------------------------------*
p1,p2 linea de p1 a p2
*
p3 el punto a consultar.
*
el mouse no es tan presiso, por eso la comparación
*
no es == a "0"(exacto)
*/
private boolean colineales(Punto a,Punto b,Punto c)
{
return (Math.abs((a.x * b.y) - (a.y * b.x) + (a.y * c.x) (a.x * c.y) + (b.x * c.y) - (b.y*c.x))<error);
}
//------------------------------------------------------------------public boolean pertenece(Punto p)
{ boolean resultado=false;
for (int i=0;i<(nPuntos-1);i++)
{
if(colineales(vertice(i),vertice(i+1),p))
{
resultado=true;
break;
}
}
return resultado;
}//fin función
//---------------------------------------------------------------public void dlgAtributos()
{
JOptionPane.showMessageDialog(null,"soy una polilinea");
}
//------------------------------------------------------------------public int[] getXCor()
{
return this.xCor;
}
//--------------------------------------------------------------------public void setXCor(int[] xCor)
{
331
Código Fuente
this.xCor = xCor;
}
//------------------------------------------------------------------public int[] getYCor()
{
return this.yCor;
}
//-------------------------------------------------------------------public void setYCor(int[] yCor)
{
this.yCor = yCor;
}
//-------------------------------------------------------------------public int getNPuntos()
{
return this.nPuntos;
}
//-------------------------------------------------------------------public void setNPuntos(int nPuntos)
{
this.nPuntos = nPuntos;
}
//------------------------------------------------------------------public Punto vertice(int i)
{
if ((i>=0) && (i<nPuntos))
{return (new Punto(xCor[i],yCor[i]));}
else
{ return null;}
}
//------------------------------------------------------------------public String toString()
{
String s="{";
for(int i=0;i<nPuntos;i++)
s+="("+xCor[i]+","+yCor[i]+")";
s+="}";
return s;
}
//------------------------------------------------------------------//Esta funcion acutaliza las propiedades de la polilinea para que
//esten acordes al nuevo Zoom
public void setZoom(int z)
{ //modificando los atributos xCor, yCor
int actual=getZoom();
332
Código Fuente
{
}
for(int i=0;i<nPuntos;i++)
xCor[i]=(xCor[i] * z)/actual;
yCor[i]=(yCor[i] * z)/actual;;
super.setZoom(z);
}
//------------------------------------------------------------------//coordenada x mas lejana al origen
public int xMayor()
{
int mayor=xCor[0];
for(int i=0;i<nPuntos;i++)
{
mayor=mayor>xCor[i]?mayor:xCor[i];
}
return mayor;
}
//-------------------------------------------------------------//coordenada y mas lejana al origen
public int yMayor()
{
int mayor=yCor[0];
for(int i=0;i<nPuntos;i++)
{
mayor=mayor>yCor[i]?mayor:yCor[i];
}
return mayor;
}
}
C.4.3.9 Clase: Punto
package figuras;
public class Punto
{ public int x, y;
//construye el punto (0,0)
public
Punto()
{
x=0;y=0;
}
//construye el punto a partir de las cordenadas x e y
public
Punto(int x, int y)
{
this.x=x;this.y=y;
}
//Construye el punto a partir de otro
public Punto(Punto P)
{
x=P.x;y=P.y;
333
Código Fuente
}
//Calcula la distancia entre el punto y otro pasado
//como argumento
public double distanciaA(Punto p)
{
int dx=p.x - this.x;
int dy=p.y - this.y;
return Math.sqrt(dx*dx+dy*dy);
}
public void asignar(Punto p)
{
x=p.x;y=p.y;
}
public void asignar(int x, int y)
{
this.x=x;this.y=y;
}
public Punto
{
return
}
public Punto
{
return
}
}
restar(Punto p)
(new Punto(x-p.x,y-p.y));
sumar(Punto p)
(new Punto(x+p.x,y+p.y));
public String toString()
{
return ("("+x+","+y+")");
}
C.4.3.10 Clase: Triangulo
package figuras;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Triangulo extends FigGeo
{ private Punto a;
private Punto b;
private Punto c;
//Constructores
//--------------------------------------------------------Triangulo()
{
super();
a=new Punto(15,20);
b=new Punto(15,100);
334
Código Fuente
c=new Punto(50,60);
}
//--------------------------------------------------------Triangulo(Punto d,Punto e,Punto f)
{
super();a=d;b=e;c=f;
}
//--------------------------------------------------------//Redefiniendo los métodos de FigGeo
public void dibujar(Graphics g)
{
int x[]={a.x,b.x,c.x};
int y[]={a.y,b.y,c.y};
g.drawPolygon(x,y,3);
}
//----------------------------------------------------------public boolean pertenece(Punto p)
{
Punto inicio,fin,direccion;
int coorx,cnt=0,np=3;
Punto q[]={a,b,c};
for(int i=0;i<np;i++)
{
inicio=p.restar(q[i%np]);
fin=p.restar(q[(i+1)%np]);
if((inicio.y * fin.y) <=0)
{
if((inicio.y!=0) || (fin.y!=0))
{
direccion = inicio.restar(fin);
coorx = (inicio.x * direccion.y inicio.y * direccion.x);
if(direccion.y<0) coorx*=-1;
if(coorx==0) {cnt =1; break;}
if(coorx > 0)
{
cnt++;
if((inicio.y < 0 && fin.y==0)||
(inicio.y==0 && fin.y<0)) cnt --;
}
}
}
}
return ((cnt %2)!=0);
}//fin función
//----------------------------------------------------------public void dlgAtributos()
{
JOptionPane.showMessageDialog(null,"soy un Triangulo");
335
Código Fuente
}
//-------------------------------------------------------------//Esta funcion acutaliza las propiedades del triangulo para
//que esten acordes al nuevo Zoom aplicando la regla de 3 simple
// por ejemplo:
//
valor actual -----> valor Actual del Zoom
//
nuevo valor -----> nuevo zoom
//
nuevo valor = (valor actual * nuevo zoom)/valor actual zoom
public void setZoom(int z)
{ //modificando los atributos a,b,c
int actual=getZoom();
a.x=(a.x * z)/actual;
a.y=(a.y * z)/actual;
b.x=(b.x * z)/actual;
b.y=(b.y * z)/actual;
c.x=(c.x * z)/actual;
c.y=(c.y * z)/actual;
super.setZoom(z);
}
//----------------------------------------------------------public int xMayor()
{return
(a.x>b.x?a.x:b.x)>c.x?(a.x>b.x?a.x:b.x):c.x;}
//-----------------------------------------------------------------public int yMayor()
{return
(a.y>b.y?a.y:b.y)>c.y?(a.y>b.y?a.y:b.y):c.y;}
//-----------------------------------------------------------------
}
public String toString()
{
return "{("+a.x+","+a.y+")("+b.x+","+b.y+")
("+c.x+","+c.y+")}";
}
336
Código Fuente
C.4.4 Paquete objcuenca
Las siguientes clases son generadas por el utilitario JPUP de Oracle a partir de
los tipos creados con CREATE TYPE. Estas clases sierven de interfaz entre
los tipos de Oracle y las clases de java.
Para cada tipo Objeto, le
corresponden dos clases java, una para acceder a las instancias del tipo y
otra para acceder a referencias del tipos. Para los tipos creados a partir de
un tipo primitivo, solamente es generada la clase para acceder a instancias:
•
AporExtracOra.java , AporExtracOraRef.java
•
AportanteOra.java, AportanteOraRef.java
•
ArrayCaudalOra.java
•
ArrCaudalesOra.java, ArrCaudalesOraRef.java,
•
ArrPuntosOra.java
•
CanalOra.java, CanalOraRef.java
•
CaptAguaPotOra.java, CaptAguaPotOraRef.java
•
CentralHidroOra.java, CentralHidroOraRef.java
•
CuadradoOra.java, CuadradoOraRef.java
•
CuencaOra.java, CuencaOraRef.java
•
ElipseOra.java, ElipseOraRef.java
•
EmbalseOra.java, EmbalseOraRef.java
•
ExtraccionOra.java, ExtraccionOraRef.java
•
FlujoOra.java, FlujoOraRef.java
•
GrafCentHidroOra.java, GrafCentHidroOraRef.java
•
GrafCuencaOra.java, GrafCuencaOraRef.java
•
GrafEmbOra.java, GrafEmbOraRef.java
•
GrafFlujoOra.java, GrafFlujoOraRef.java
•
GrafNodoOra.java, GrafNodoOraRef.java
•
HoyaInterOra.java, HoyaInterOraRef.java
•
NodoOra.java, NodoOraRef.java
•
PolilineaOra.java, PolilineaOraRef.java
•
PuntoOra.java, PuntoOraRef.java
•
RegimenNaturalOra.java, RegimenNaturalOraRef.java
•
RioOra.java, RioOraRef.java
•
SalidaEmbOra.java, SalidaEmbOraRef.java
337
Código Fuente
•
TramoOra.java, TramoOraRef.java
•
TrianguloOra.java, TrianguloOraRef.java
Acada una de estas clases, le agregamos una línea de código para indicar que
pertenecen al paquete objcuenca. Por ser muy extensas y poco claras, sólo
mostraremos dos de estas clases: AporExtracOra.java, AporExtracOraRef.java.
El paquete objcuenca consta de 58 clases, donde 4 de ellas no son generadas
por las utilidades de Oracle. Estas son:
•
BDObjCuenca.java
•
GuiEmbalse.java
•
GuiFlujo.java
•
GuiNodo.java
Estas clases si son mostradas.
C.4.4.1 Clase: AporExtracOra
package objcuenca;//linea agregada manualmente
/*@lineinfo:filename=AporExtracOra*/
/*@lineinfo:user-code*/
/*@lineinfo:1^1*/
import
import
import
import
import
import
import
import
import
import
import
java.sql.SQLException;
Oracle.jdbc.driver.OracleConnection;
Oracle.jdbc.driver.OracleTypes;
Oracle.sql.CustomDatum;
Oracle.sql.CustomDatumFactory;
Oracle.sql.Datum;
Oracle.sql.STRUCT;
Oracle.jpub.runtime.MutableStruct;
sqlj.runtime.ref.DefaultContext;
sqlj.runtime.ConnectionContext;
java.sql.Connection;
public class AporExtracOra implements CustomDatum, CustomDatumFactory
{
public static final String _SQL_NAME = "APOR_EXTRAC";
public static final int _SQL_TYPECODE = OracleTypes.STRUCT;
/*@lineinfo:generated-code*//*@lineinfo:18^3*/
//
//
//
************************************************************
SQLJ context declaration:
************************************************************
static class _Ctx
338
Código Fuente
extends sqlj.runtime.ref.ConnectionContextImpl
implements sqlj.runtime.ConnectionContext
{
public _Ctx(java.sql.Connection conn)
throws java.sql.SQLException
{
super(profiles, conn);
}
public _Ctx(java.lang.String url, java.lang.String user,
java.lang.String password, boolean autoCommit)
throws java.sql.SQLException
{
super(profiles, url, user, password, autoCommit);
}
public _Ctx(java.lang.String url, java.util.Properties info, boolean
autoCommit)
throws java.sql.SQLException
{
super(profiles, url, info, autoCommit);
}
public _Ctx(java.lang.String url, boolean autoCommit)
throws java.sql.SQLException
{
super(profiles, url, autoCommit);
}
public _Ctx(sqlj.runtime.ConnectionContext other)
throws java.sql.SQLException
{
super(profiles, other);
}
public static _Ctx getDefaultContext()
{
if (defaultContext == null)
{
java.sql.Connection conn =
sqlj.runtime.RuntimeContext.getRuntime().getDefaultConnection();
if (conn != null)
{
try
{
defaultContext = new _Ctx(conn);
}
catch (java.sql.SQLException e)
{
}
}
}
return defaultContext;
}
public static void setDefaultContext(_Ctx ctx)
{
defaultContext = ctx;
}
private static _Ctx defaultContext = null;
339
Código Fuente
public static java.lang.Object
getProfileKey(sqlj.runtime.profile.Loader loader, java.lang.String
profileName)
throws java.sql.SQLException
{
return profiles.getProfileKey(loader, profileName);
}
private static final sqlj.runtime.ref.ProfileGroup profiles = new
sqlj.runtime.ref.ProfileGroup();
public static sqlj.runtime.profile.Profile getProfile(java.lang.Object
profileKey)
{
return profiles.getProfile(profileKey);
}
}
//
************************************************************
/*@lineinfo:user-code*//*@lineinfo:18^26*/
_Ctx _ctx;
static int[] _sqlType =
{
2, 2002, 2002, 2002
};
static CustomDatumFactory[] _factory = new CustomDatumFactory[4];
static
{
_factory[1] = CanalOra.getFactory();
_factory[2] = TramoOra.getFactory();
_factory[3] = CentralHidroOra.getFactory();
}
MutableStruct _struct;
static final AporExtracOra _AporExtracOraFactory = new
AporExtracOra();
public static CustomDatumFactory getFactory()
{
return _AporExtracOraFactory;
}
/* constructors */
public AporExtracOra()
{
_struct = new MutableStruct(new Object[4], _sqlType, _factory);
try
{
_ctx = new _Ctx(DefaultContext.getDefaultContext());
}
catch (Exception e)
{
340
Código Fuente
}
}
_ctx = null;
public AporExtracOra(ConnectionContext c) throws SQLException
{
_struct = new MutableStruct(new Object[4], _sqlType, _factory);
_ctx = new _Ctx(c == null ? DefaultContext.getDefaultContext()
: c);
}
public AporExtracOra(Connection c) throws SQLException
{
_struct = new MutableStruct(new Object[4], _sqlType, _factory);
_ctx = new _Ctx(c);
}
/* CustomDatum interface */
public Datum toDatum(OracleConnection c) throws SQLException
{
_ctx = new _Ctx(c);
return _struct.toDatum(c, _SQL_NAME);
}
/* CustomDatumFactory interface */
public CustomDatum create(Datum d, int sqlType) throws SQLException
{
if (d == null) return null;
AporExtracOra o = new AporExtracOra();
o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);
o._ctx = new _Ctx(((STRUCT) d).getConnection());
return o;
}
/* shallow copy method: give object same attributes as argument */
void shallowCopy(AporExtracOra d) throws SQLException
{
_struct = d._struct;
}
/* accessor methods */
public java.math.BigDecimal getTipo() throws SQLException
{ return (java.math.BigDecimal) _struct.getAttribute(0); }
public void setTipo(java.math.BigDecimal tipo) throws SQLException
{ _struct.setAttribute(0, tipo); }
public CanalOra getCa() throws SQLException
{ return (CanalOra) _struct.getAttribute(1); }
public void setCa(CanalOra ca) throws SQLException
{ _struct.setAttribute(1, ca); }
341
Código Fuente
public TramoOra getTr() throws SQLException
{ return (TramoOra) _struct.getAttribute(2); }
public void setTr(TramoOra tr) throws SQLException
{ _struct.setAttribute(2, tr); }
public CentralHidroOra getCh() throws SQLException
{ return (CentralHidroOra) _struct.getAttribute(3); }
public void setCh(CentralHidroOra ch) throws SQLException
{ _struct.setAttribute(3, ch); }
public java.math.BigDecimal demanda (
java.math.BigDecimal caudal,
java.math.BigDecimal m)
throws SQLException
{
AporExtracOra __jPt_temp = this;
java.math.BigDecimal __jPt_result;
/*@lineinfo:generated-code*//*@lineinfo:127^5*/
//
//
//
//
//
//
//
//
************************************************************
#sql [_ctx] { BEGIN
:__jPt_result := :__jPt_temp.DEMANDA(
:caudal,
:m);
END;
};
************************************************************
{
sqlj.runtime.ConnectionContext __sJT_connCtx = _ctx;
if (__sJT_connCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
sqlj.runtime.ExecutionContext __sJT_execCtx =
__sJT_connCtx.getExecutionContext();
if (__sJT_execCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
AporExtracOra __sJT_2 = __jPt_temp;
java.math.BigDecimal __sJT_3 = caudal;
java.math.BigDecimal __sJT_4 = m;
synchronized (__sJT_execCtx) {
sqlj.runtime.profile.RTStatement __sJT_stmt =
__sJT_execCtx.registerStatement(__sJT_connCtx,
AporExtracOra_SJProfileKeys.getKey(0), 0);
try
{
__sJT_stmt.setObject(2, __sJT_2);
__sJT_stmt.setBigDecimal(3, __sJT_3);
__sJT_stmt.setBigDecimal(4, __sJT_4);
__sJT_execCtx.executeUpdate();
__jPt_result = __sJT_stmt.getBigDecimal(1);
342
Código Fuente
}
}
//
}
finally
{
__sJT_execCtx.releaseStatement();
}
************************************************************
/*@lineinfo:user-code*//*@lineinfo:133^5*/
return __jPt_result;
}
public void entrada (
java.math.BigDecimal caudal,
java.math.BigDecimal m)
throws SQLException
{
AporExtracOra __jPt_temp = this;
/*@lineinfo:generated-code*//*@lineinfo:143^5*/
//
//
//
//
//
//
//
//
************************************************************
#sql [_ctx] { BEGIN
:__jPt_temp.ENTRADA(
:caudal,
:m);
END;
};
************************************************************
{
sqlj.runtime.ConnectionContext __sJT_connCtx = _ctx;
if (__sJT_connCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
sqlj.runtime.ExecutionContext __sJT_execCtx =
__sJT_connCtx.getExecutionContext();
if (__sJT_execCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
AporExtracOra __sJT_1 = __jPt_temp;
java.math.BigDecimal __sJT_2 = caudal;
java.math.BigDecimal __sJT_3 = m;
synchronized (__sJT_execCtx) {
sqlj.runtime.profile.RTStatement __sJT_stmt =
__sJT_execCtx.registerStatement(__sJT_connCtx,
AporExtracOra_SJProfileKeys.getKey(0), 1);
try
{
__sJT_stmt.setObject(1, __sJT_1);
__sJT_stmt.setBigDecimal(2, __sJT_2);
__sJT_stmt.setBigDecimal(3, __sJT_3);
__sJT_execCtx.executeUpdate();
343
Código Fuente
__jPt_temp = ((AporExtracOra)(__sJT_stmt.getObject(1,
AporExtracOra.class)));
}
finally
{
__sJT_execCtx.releaseStatement();
}
}
}
//
************************************************************
/*@lineinfo:user-code*//*@lineinfo:149^5*/
shallowCopy(__jPt_temp);
}
public java.math.BigDecimal salida (
java.math.BigDecimal m)
throws SQLException
{
AporExtracOra __jPt_temp = this;
java.math.BigDecimal __jPt_result;
/*@lineinfo:generated-code*//*@lineinfo:159^5*/
//
//
//
//
//
//
//
************************************************************
#sql [_ctx] { BEGIN
:__jPt_result := :__jPt_temp.SALIDA(
:m);
END;
};
************************************************************
{
sqlj.runtime.ConnectionContext __sJT_connCtx = _ctx;
if (__sJT_connCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
sqlj.runtime.ExecutionContext __sJT_execCtx =
__sJT_connCtx.getExecutionContext();
if (__sJT_execCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
AporExtracOra __sJT_2 = __jPt_temp;
java.math.BigDecimal __sJT_3 = m;
synchronized (__sJT_execCtx) {
sqlj.runtime.profile.RTStatement __sJT_stmt =
__sJT_execCtx.registerStatement(__sJT_connCtx,
AporExtracOra_SJProfileKeys.getKey(0), 2);
try
{
__sJT_stmt.setObject(2, __sJT_2);
__sJT_stmt.setBigDecimal(3, __sJT_3);
__sJT_execCtx.executeUpdate();
__jPt_result = __sJT_stmt.getBigDecimal(1);
}
344
Código Fuente
}
}
//
finally
{
__sJT_execCtx.releaseStatement();
}
************************************************************
/*@lineinfo:user-code*//*@lineinfo:164^5*/
return __jPt_result;
}
public String tovarchar2 ()
throws SQLException
{
AporExtracOra __jPt_temp = this;
String __jPt_result;
/*@lineinfo:generated-code*//*@lineinfo:173^5*/
//
//
//
//
//
//
************************************************************
#sql [_ctx] { BEGIN
:__jPt_result := :__jPt_temp.TOVARCHAR2();
END;
};
************************************************************
{
sqlj.runtime.ConnectionContext __sJT_connCtx = _ctx;
if (__sJT_connCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_CONN_CTX();
sqlj.runtime.ExecutionContext __sJT_execCtx =
__sJT_connCtx.getExecutionContext();
if (__sJT_execCtx == null)
sqlj.runtime.error.RuntimeRefErrors.raise_NULL_EXEC_CTX();
AporExtracOra __sJT_2 = __jPt_temp;
synchronized (__sJT_execCtx) {
sqlj.runtime.profile.RTStatement __sJT_stmt =
__sJT_execCtx.registerStatement(__sJT_connCtx,
AporExtracOra_SJProfileKeys.getKey(0), 3);
try
{
__sJT_stmt.setObject(2, __sJT_2);
__sJT_execCtx.executeUpdate();
__jPt_result = __sJT_stmt.getString(1);
}
finally
{
__sJT_execCtx.releaseStatement();
}
}
}
345
Código Fuente
//
************************************************************
/*@lineinfo:user-code*//*@lineinfo:177^5*/
return __jPt_result;
}
}/*@lineinfo:generated-code*/class AporExtracOra_SJProfileKeys
{
private static AporExtracOra_SJProfileKeys inst = null;
public static java.lang.Object getKey(int keyNum)
throws java.sql.SQLException
{
if (inst == null)
{
inst = new AporExtracOra_SJProfileKeys();
}
return inst.keys[keyNum];
}
private final sqlj.runtime.profile.Loader loader =
sqlj.runtime.RuntimeContext.getRuntime().getLoaderForClass(getClass());
private java.lang.Object[] keys;
private AporExtracOra_SJProfileKeys()
throws java.sql.SQLException
{
keys = new java.lang.Object[1];
keys[0] = AporExtracOra._Ctx.getProfileKey(loader,
"objcuenca/AporExtracOra_SJProfile0");
}
}
C.4.4.2 Clase: AporExtracOraRef
package objcuenca; //linea agregada manualmente
import
import
import
import
import
import
import
import
java.sql.SQLException;
Oracle.jdbc.driver.OracleConnection;
Oracle.jdbc.driver.OracleTypes;
Oracle.sql.CustomDatum;
Oracle.sql.CustomDatumFactory;
Oracle.sql.Datum;
Oracle.sql.REF;
Oracle.sql.STRUCT;
public class AporExtracOraRef implements CustomDatum, CustomDatumFactory
{
public static final String _SQL_BASETYPE = "APOR_EXTRAC";
public static final int _SQL_TYPECODE = OracleTypes.REF;
REF _ref;
static final AporExtracOraRef _AporExtracOraRefFactory =
new AporExtracOraRef();
public static CustomDatumFactory getFactory()
{
346
Código Fuente
}
return _AporExtracOraRefFactory;
/* constructor */
public AporExtracOraRef()
{
}
/* CustomDatum interface */
public Datum toDatum(OracleConnection c) throws SQLException
{
return _ref;
}
/* CustomDatumFactory interface */
public CustomDatum create(Datum d, int sqlType) throws SQLException
{
if (d == null) return null;
AporExtracOraRef r = new AporExtracOraRef();
r._ref = (REF) d;
return r;
}
public AporExtracOra getValue() throws SQLException
{
return (AporExtracOra) AporExtracOra.getFactory().create(
(Datum) _ref.getValue(), OracleTypes.REF);
}
}
public void setValue(AporExtracOra c) throws SQLException
{
_ref.setValue((STRUCT) c.toDatum(_ref.getConnection()));
}
347
Código Fuente
C.4.4.3 Clase: BDObjCuenca
package objcuenca;
import java.sql.*;
import Oracle.jdbc2.*;
import Oracle.sql.*;
import Oracle.jdbc.driver.*;
import Oracle.jdbc.oracore.*;
import Oracle.sqlj.runtime.Oracle;
import Oracle.sqlj.runtime.util.*;
import consultorSql.ConectorJDBC;
import java.util.Vector;
import java.util.Dictionary;
import objcuenca.*;
public class BDObjCuenca extends ConectorJDBC
{
/**
* Constructor Generico.
*/
public BDObjCuenca()
{
super();
}
/**
* Constructor con parametros de coneccion.
*/
public BDObjCuenca(String url, String driverName,
String user, String passwd)
{
super(url,driverName,user,passwd);
}
/*********************************************************************
* Obtiene desde la base de datos un objeto del tipo CuencaOraRef a
* partir del codigo del objeto al que referencia.
*/
public CuencaOraRef
getCuencaRef(String codigo) throws Exception
{
PreparedStatement st=
getConnection().prepareStatement(
"SELECT ref(c) FROM tbl_cuenca c where c.codigo=(?)") ;
st.setObject(1,codigo,OracleTypes.VARCHAR) ;
st.executeQuery();
OracleResultSet rs = (OracleResultSet) st.getResultSet() ;
rs.next() ;
CuencaOraRef cuencaRef= new CuencaOraRef();
cuencaRef._ref =rs.getREF(1);
return cuencaRef;
}
/**
* Obtiene desde la base de datos un objeto del tipo RioOraRef
* del codigo del objeto al que referencia.
*/
public RioOraRef getRioRef(String codigo)
348
Código Fuente
{
try
{
PreparedStatement st=
getConnection().prepareStatement(
"SELECT ref(r) FROM tbl_rio r where r.codigo=(?)") ;
st.setObject(1,codigo,OracleTypes.VARCHAR) ;
st.executeQuery();
OracleResultSet rs = (OracleResultSet) st.getResultSet() ;
rs.next() ;
RioOraRef rioRef= new RioOraRef();
rioRef._ref =rs.getREF(1);
return rioRef;
}
catch (Exception err)
{
err.printStackTrace(System.err);
return null;
}
}
/**
* Obtiene desde la base de datos un objeto del tipo CuencaOra a
* partir de su codigo
*/
public CuencaOra getCuenca(String codigo) throws Exception
{
CuencaOraRef cuencaRef=getCuencaRef(codigo);
return cuencaRef.getValue();
}
/**
* Obtiene los nodos de la cuenca. y los debuelve
* en un vector. Se entrega un NodoOraRef
*/
public Vector getAllNodoOraRef(CuencaOra c) throws Exception
{
Vector nodos=new Vector();
PreparedStatement st=
getConnection().prepareStatement(
" SELECT ref(n) " +
" FROM tbl_nodo n"+
" where n.myCuenca = "+
"
(SELECT ref(c) FROM tbl_cuenca c where c.codigo=(?))"
);
st.setObject(1,c.getCodigo(),OracleTypes.VARCHAR) ;
st.executeQuery();
OracleResultSet rs = (OracleResultSet) st.getResultSet() ;
while(rs.next())
{
GuiNodo guiNodoRef=new GuiNodo();
guiNodoRef._ref=rs.getREF(1);
guiNodoRef.loadFigura();
nodos.add(guiNodoRef) ;
349
Código Fuente
}
}
return nodos;
/**
* Obtiene los embalses de la cuenca. y los debuelve
* en un vector. Se entrega un EmbalseOraRef
*/
public Vector getAllEmbalseOraRef(CuencaOra c) throws Exception
{
Vector embalses=new Vector();
PreparedStatement st=
getConnection().prepareStatement(
" SELECT ref(e) " +
" FROM tbl_emb e"+
" where e.myNodo.myCuenca.codigo = ?") ;
st.setObject(1,c.getCodigo(),OracleTypes.VARCHAR) ;
st.executeQuery();
OracleResultSet rs = (OracleResultSet) st.getResultSet() ;
while(rs.next())
{
GuiEmbalse emb=new GuiEmbalse();
emb._ref=rs.getREF(1);
emb.loadFigura();
embalses.add(emb) ;
}
return embalses;
}
/**
* Obtiene los Flujos de la y los debuelve
* en un vector. Se entrega un FlujoOraRef
*/
public Vector getAllFlujosOraRef(CuencaOra c) throws Exception
{
Vector vector=new Vector();
PreparedStatement st=
getConnection().prepareStatement(
" SELECT ref(f) " +
" FROM tbl_flujo f"+
" where f.nodo_ini.myCuenca.codigo = ?"+
"
or f.nodo_fin.myCuenca.codigo = ?") ;
st.setObject(1,c.getCodigo(),OracleTypes.VARCHAR) ;
st.setObject(2,c.getCodigo(),OracleTypes.VARCHAR) ;
st.executeQuery();
OracleResultSet rs = (OracleResultSet) st.getResultSet() ;
while(rs.next())
{
GuiFlujo figura=new GuiFlujo();
figura._ref=rs.getREF(1);
figura.loadFigura();
vector.add(figura) ;
350
Código Fuente
}
}
return vector;
/**
* obtiene todas las figuras de la cuenca.
*
*/
public Vector getAllFigRef(CuencaOra c) throws Exception
{
Vector vector=getAllNodoOraRef(c);
vector.addAll(getAllEmbalseOraRef(c));
vector.addAll(getAllFlujosOraRef(c));
return vector;
}
/**
* Inserta una cuenca a la base de datos
*/
public void Insertar(CuencaOra c) throws SQLException
{
PreparedStatement st=
getConnection().prepareStatement(
" INSERT INTO tbl_cuenca" +
" VALUES (cuenca(?,?))"
);
st.setObject(1,c.getCodigo(),OracleTypes.VARCHAR) ;
st.setObject(2,c.getNombre(),OracleTypes.VARCHAR) ;
st.executeQuery();
}
/**
* Inserta un rio a la base de datos.
*/
public void Insertar(RioOra c) throws SQLException
{
PreparedStatement st=
getConnection().prepareStatement(
" INSERT INTO tbl_rio" +
" VALUES (rio(?,?))"
);
st.setObject(1,c.getCodigo(),OracleTypes.VARCHAR) ;
st.setObject(2,c.getNombre(),OracleTypes.VARCHAR) ;
st.executeQuery();
}
/**
* Eliminar cuenca.
*/
public void eliminar(CuencaOra c) throws SQLException
351
Código Fuente
{
}
PreparedStatement st=
getConnection().prepareStatement(
" DELETE FROM tbl_cuenca c" +
" WHERE c.codigo=?"
);
st.setObject(1,c.getCodigo().trim(),OracleTypes.VARCHAR) ;
st.executeQuery();
/**
* Eliminar Rio
*/
public void eliminar(RioOra c) throws SQLException
{
PreparedStatement st=
getConnection().prepareStatement(
" DELETE FROM tbl_rio r" +
" WHERE r.codigo=?"
);
st.setObject(1,c.getCodigo().trim(),OracleTypes.VARCHAR) ;
st.executeQuery();
}
/**
* Insertar un Canal
*
*
*/
public GuiFlujo insertar(FlujoOra flujo) throws SQLException
{
OracleCallableStatement ocs= (OracleCallableStatement)
getConnection().prepareCall("{ ? = call Insert_Flujo(?) }");
}
ocs.registerOutParameter(1,OracleTypes.REF,"FLUJO");
ocs.setCustomDatum(2,flujo);
ocs.execute();
GuiFlujo guiFlujo=new GuiFlujo();
guiFlujo._ref =ocs.getREF(1);
return guiFlujo;
}
352
Código Fuente
C.4.4.4 Clase: GuiEmbalse
package objcuenca;
import
import
import
import
import
import
import
objcuenca.*;
java.awt.Dimension;
javax.swing.JOptionPane;
java.sql.SQLException;
java.math.*;
cuencamaule.frmEmbalse;
figuras.*;
public class GuiEmbalse extends EmbalseOraRef implements Graficable
{
private int zoom=100;
private GrafEmbOra graf;
private String Codigo;
private frmEmbalse frm;
private boolean alerta=false;
public GuiEmbalse()
{
}
/**----------------------------------------------------------------*
Carga la figura que reprecenta al embaslse
*/
public void loadFigura()
{
try
{
int zoomAct=zoom;
EmbalseOra em=this.getValue();
//la figura almacenada en la base de datos, esta al 100%
zoom=100;
graf=em.getGraf();
Codigo=em.getCodigo();
this.alerta=alertaEmb();
// restauro el valor del zoom,
// y se ajusta la figura que estaba al100%
setZoom(zoomAct);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
// implementacion metodos de la interfaz Graficable
/**
* Cambia el valor del zoom con el pasado como parametro
*/
public void setZoom(int zoom)
{
353
Código Fuente
try
{
TrianguloOra tr=graf.getTr() ;
PuntoOra a=tr.getA() ;
PuntoOra b=tr.getB() ;
PuntoOra c=tr.getC() ;
double X;double Y; int actual=getZoom();
//aplicando el zoom al punto a
X = a.getX().doubleValue() ;
Y = a.getY().doubleValue() ;
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
a.setX(new BigDecimal(X));
a.setY(new BigDecimal(Y));
//aplicando el zoom al punto b
X = b.getX().doubleValue() ;
Y = b.getY().doubleValue() ;
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
b.setX(new BigDecimal(X));
b.setY(new BigDecimal(Y));
//aplicando el zoom al punto c
X = c.getX().doubleValue() ;
Y = c.getY().doubleValue() ;
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
c.setX(new BigDecimal(X));
c.setY(new BigDecimal(Y));
tr.setA(a);
tr.setB(b);
tr.setC(c) ;
graf.setTr(tr);
this.zoom=zoom;
}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
/**********************************************************
* Entrega el Zoom actual
*
*/
public int getZoom()
{
return zoom;
354
Código Fuente
}
private boolean alertaEmb()
{
try
{
ArrCaudalesOra curAler=this.getValue().getCurvaAlerta();
ArrCaudalesOra caudal =this.getValue().getCaudales();
boolean colorCambiado=false;
for(int i=1;i<=6;i++)
{
if(curAler.getcaudal(new BigDecimal(i)).compareTo(
caudal.getcaudal(new BigDecimal(i)))==1)
{
return true;
}
}
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,"Error en el embalse : "
+ex.getMessage()) ;
}
return false;
}
/***********************************************************
* Dibuja un triangulo que reprecenta al embalse
*
*/
public void dibujar(Dibujante d)
{
try
{
if(alerta){d.setColorLinea(java.awt.Color.red);}
TrianguloOra tr=graf.getTr() ;
d.drawTriangulo(tr) ;
PuntoOra poA=tr.getA() ;
PuntoOra poB=tr.getB() ;
PuntoOra poC=tr.getC() ;
Punto a=new Punto(
poA.getX().intValue(),poA.getY().intValue());
Punto b=new Punto(
poB.getX().intValue(),poB.getY().intValue());
Punto c=new Punto(
poC.getX().intValue(),poC.getY().intValue());
a.x=c.x;
int an = (int) b.distanciaA(c);
int alturaTriangulo = (int) a.distanciaA(c) ;
int al = alturaTriangulo/2;
int x=b.x;
int y=b.y-(alturaTriangulo/2);
355
Código Fuente
//las constantes 3 y 22 furon obtenidas empiricamente.
int tamfuente=an*3/22;
if(Codigo.length() >0)
{
d.drawCenteredString(Codigo ,x,y,an, al,tamfuente);
d.drawCenteredString("F Ee R
Er G",
b.x,b.y,an,al*2/3,tamfuente);
}
if(alerta){d.setColorLinea(java.awt.Color.black);}
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
/***********************************************************
* Despliega el dialogo para modificar los atributos del
* nodo
*
*/
public void dlgAtributos()
{
try
{
PuntoOra poA=graf.getTr().getA();
frm=new frmEmbalse(this);
frm.setLocation(poA.getX().intValue() , poA.getY().intValue());
frm.pack() ;
frm.show() ;
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
/************************************************************
* Entrega la dimencion minima para el contenedor
* del embalse
*
*/
public Dimension dimensionMinima()
{
try
{
int x=graf.getTr().getC().getX().intValue() ;
int y=graf.getTr().getC().getY().intValue() ;
return (new Dimension(x,y));
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
356
Código Fuente
}
return null;
}
/************************************************************
* Entrega Verdadero si el punto pasado por parametro
* percenece al triangulo o falso si no pertenece.
*/
public boolean pertenece(Punto p)
{
try
{
TrianguloOra tr=graf.getTr() ;
PuntoOra poA=tr.getA() ;
PuntoOra poB=tr.getB() ;
PuntoOra poC=tr.getC() ;
Punto a=new Punto(
poA.getX().intValue(),poA.getY().intValue() );
Punto b=new Punto(
poB.getX().intValue(),poB.getY().intValue() );
Punto c=new Punto(
poC.getX().intValue(),poC.getY().intValue() );
Punto inicio,fin,direccion;
int coorx,cnt=0,np=3;
Punto q[]={a,b,c};
for(int i=0;i<np;i++)
{
inicio=p.restar(q[i%np]); fin=p.restar(q[(i+1)%np]);
if((inicio.y * fin.y) <=0)
{
if((inicio.y!=0) || (fin.y!=0))
{
direccion = inicio.restar(fin);
coorx = (inicio.x * direccion.y inicio.y * direccion.x);
if(direccion.y<0) coorx*=-1;
if(coorx==0) {cnt =1; break;}
if(coorx > 0)
{
cnt++;
if((inicio.y < 0 && fin.y==0)||
(inicio.y==0 && fin.y<0)) cnt --;
}
}
}
}
return ((cnt %2)!=0);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
return false;
}
}
}
357
Código Fuente
C.4.4.5 Clase: GuiFlujo
package objcuenca;
import objcuenca.*;
import java.awt.Dimension;
import javax.swing.JOptionPane;
import java.sql.SQLException;
import java.math.*;
import cuencamaule.*;
import figuras.*;
public class GuiFlujo extends FlujoOraRef implements Graficable
{
private int
zoom=100;
private GrafCuencaOra graf;
private frmFlujo
frm;
private boolean
alerta=false;
/**
* Constructor por defecto.
*/
public GuiFlujo()
{
}
//Carga la figura que reprecenta al flujo
public void loadFigura()
{
try
{
//Como vamos a leer la figura desde la base de datos, debemos
//ajustarla al valor del zoom actual. Para esto guardo el zoom.
int zoomAct=zoom;
//la figura almacenada en la base de datos, esta al 100%
zoom=100;
graf=this.getValue().getGraf();
// restauro el valor del zoom, y se ajusta la figura que
// estaba al100%
this.alerta=alertaFlujo();
setZoom(zoomAct);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
358
Código Fuente
// ajuste de Zoom para una figura del tipo GrafCentHidroOra
private void setZoomCentHidro(int zoom)
{
try
{
GrafCentHidroOra gch=graf.getGch();
PolilineaOra pl1=graf.getGch().getPl1();
PolilineaOra pl2=graf.getGch().getPl2();
//ajustando zoom polilineas
int cont=0;
PolilineaOra pl=pl1;
while(cont!=2)
{
int actual=getZoom();
int largo=pl.getNpuntos().intValue();
double X,Y;
PuntoOra a;
int i;
for(i=1;i<=largo;i++)
{
a=pl.getp(new BigDecimal(i));
X = a.getX().doubleValue()
;
Y = a.getY().doubleValue() ;
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
a.setX(new BigDecimal(X));
a.setY(new BigDecimal(Y));
pl.setp(a,new BigDecimal(i));
}
pl=pl2;
cont++;
}
gch.setPl1(pl1);
gch.setPl2(pl2);
CuadradoOra cuad=graf.getGch().getCuad();
PuntoOra a=graf.getGch().getCuad().getA()
PuntoOra b=graf.getGch().getCuad().getB()
PuntoOra c=graf.getGch().getCuad().getC()
PuntoOra d=graf.getGch().getCuad().getD()
//ajustando puntos del cuadrado.
PuntoOra p=a ;
cont=0;
while(cont != 4)
{
double X = p.getX().doubleValue()
;
double Y = p.getY().doubleValue() ;
int actual=getZoom();
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
p.setX(new BigDecimal(X));
p.setY(new BigDecimal(Y));
cont++;
switch (cont)
;
;
;
;
359
Código Fuente
{
case 1:
p=b;
break;
case 2:
p=c;
break;
case 3:
p=d;
break;
}
}
cuad.setA(a);
cuad.setB(b);
cuad.setC(c);
cuad.setD(d);
gch.setCuad(cuad);
graf.setGch(gch);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
// aplica el zoom a un GrafFlujoOra
private void setZoomGrafFlujo(int zoom)
{
try
{
int actual=getZoom();
int largo=graf.getGfl().getPl().length();
double X,Y;
PuntoOra a;
for(int i=0;i<largo;i++)
{
a=graf.getGfl().getPl().getElement(i) ;
X = a.getX().doubleValue()
;
Y = a.getY().doubleValue() ;
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
a.setX(new BigDecimal(X));
a.setY(new BigDecimal(Y));
graf.getGfl().getPl().setElement(a,i) ;
}
}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
360
Código Fuente
//
implementacion metodos de la interfaz Graficable
public void setZoom(int zoom)
{
try
{
if ((graf != null)&&(graf.getTipo() != null))
{
switch (graf.getTipo().intValue()) {
case 1:
setZoomGrafFlujo(zoom);
break;
case 2:
setZoomCentHidro(zoom);
break;
}
this.zoom=zoom;
}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
/**********************************************************
* Entrega el Zoom actual
*
*/
public int getZoom()
{
return zoom;
}
/***********************************************************
* Dibuja un flujo.
*/
private void dibujarFlujo(Dibujante d)
{
try
{
ArrPuntosOra arrp=graf.getGfl().getPl();
switch (graf.getGfl().getEstilo().intValue())
{
case 1:
//linea simple
d.drawPolilinea(arrp) ;
break;
case 2:
//linea doble
d.drawPolilineaDoble(arrp) ;
break;
361
Código Fuente
case 3:
//gruesa
d.drawPolilineaGruesa(arrp) ;
break;
}
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
/*********************************************************
* Dibuja una Central Hidroelectrica.
*/
private void dibujarCentHidro(Dibujante d)
{
try
{
GrafCentHidroOra ch=graf.getGch();
d.drawCuadrado(ch.getCuad());
d.drawPolilinea(ch.getPl1());
d.drawPolilinea(ch.getPl2().getLospuntos());
}
catch (Exception err)
{
err.printStackTrace(System.err) ;
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
/***********************************************************
* Dibuja el flujo correspondiente.
*
*/
public void dibujar(Dibujante d)
{
if(alerta){d.setColorLinea(java.awt.Color.red);}
try
{
if((graf!=null)&&(graf.getTipo()!=null))
{
switch (graf.getTipo().intValue())
{
case 1:
dibujarFlujo(d);
break;
case 2:
dibujarCentHidro(d);
int ax=graf.getGch().getCuad().getA().getX().intValue();
362
Código Fuente
}
}
int ay=graf.getGch().getCuad().getA().getY().intValue();
int bx=graf.getGch().getCuad().getB().getX().intValue();
int by=graf.getGch().getCuad().getB().getY().intValue();
int cx=graf.getGch().getCuad().getC().getX().intValue();
int cy=graf.getGch().getCuad().getC().getY().intValue();
int dx=graf.getGch().getCuad().getD().getX().intValue();
int dy=graf.getGch().getCuad().getD().getY().intValue();
int al=Math.abs(cy - ay);
int an=Math.abs(bx - ax);
int x=ax ;
int y=ay ;
int tamfuente=an*9/24;
d.drawCenteredString("C" ,x,y,an, al,tamfuente);
break;
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
if(alerta){d.setColorLinea(java.awt.Color.black);}
}
/***********************************************************
* Despliega el dialogo para modificar los atributos del
* flujo
*
*/
public void dlgAtributos()
{
try
{
FlujoOra fl=this.getValue();
switch (fl.getTipo().intValue())
{
case 1://aportante
if(fl.getAp().getTipo().intValue()==1)
{
frm=new frmHoyaInter(this);
break;
}
else
{
if(fl.getAp().getTipo().intValue()==2)
{
frm=new frmRegNat(this);
break;
}
else
{
if(fl.getAp().getTipo().intValue()==3)
{
363
Código Fuente
}
}
frm=new frmSalidaEmb(this);
break;
}
break;
case 2://extracción
if(fl.getEx().getTipo().intValue() == 1 )
{
frm=new FrmCapAguaPot(this);
break;
}
case 3://aportante y extractor
if(fl.getApex().getTipo().intValue() ==1 )
{//si es un canal.
frm=new FrmCanal(this);
break;
}
else
{
if(fl.getApex().getTipo().intValue() ==2)
{//si es un tramo.
frm=new FrmTramo(this);
break;
}
else
{
if(fl.getApex().getTipo().intValue()==3)
{// si es una central hidroelectrica.
frm=new FrmCentralHidro(this);
break;
}
}
}
default:
frm=new frmFlujo();
break;
}
frm.pack() ;
frm.show() ;
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
}
}
364
Código Fuente
/**
* Entrega la dimension minima para el contenedor de los
* puntos en arr
*/
private Dimension dimensionMinimaGFlujo()
{
try
{
int x=0; int px=0;
int y=0; int py=0;
int largo=graf.getGfl().getPl().length();
for (int i = 0; i < largo; i++)
{
px=graf.getGfl().getPl().getElement(i).getX().intValue();
py=graf.getGfl().getPl().getElement(i).getY().intValue();
x=x>px?x:px;
y=y>py?y:py;
}
return new Dimension(x,y);
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace(System.err) ;
return new Dimension(0,0);
}
}
private Dimension dimensionMinima(PolilineaOra fl)
{
try
{
int x=0; int px=0;
int y=0; int py=0;
int largo=fl.getLospuntos().length();
for (int i = 0; i < largo; i++)
{
px=fl.getLospuntos().getElement(i).getX().intValue();
py=fl.getLospuntos().getElement(i).getY().intValue();
x=x>px?x:px;
y=y>py?y:py;
}
return new Dimension(x,y);
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace(System.err) ;
return new Dimension(0,0);
}
}
365
Código Fuente
/**
* Entrega la dimension minima para el contenedor la central
* hidroelectrica
*/
private Dimension dimensionMinimaCH()
{
try
{
GrafCentHidroOra gch=graf.getGch() ;
Dimension d1=dimensionMinima(gch.getPl1());
Dimension d2=dimensionMinima(gch.getPl2());
PuntoOra p=gch.getCuad().getD();
Dimension d3=new Dimension(
p.getX().intValue(),p.getY().intValue());
int x=Math.max(d1.width , Math.max(d2.width,d3.width));
int y=Math.max(d1.height , Math.max(d2.height,d3.height));
return new Dimension(x,y);
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace(System.err) ;
return new Dimension(0,0);
}
}
/************************************************************
* Entrega la dimencion minima para el contenedor
* del nodo
*
*/
public Dimension dimensionMinima()
{
try
{
Dimension d=new Dimension(0,0);
if((graf!=null)&&(graf.getTipo()!=null))
{
switch (graf.getTipo().intValue())
{
case 1:
d=dimensionMinimaGFlujo();
break;
case 2:
d=dimensionMinimaCH();
break;
}
}
return d;
}
catch (SQLException err)
366
Código Fuente
{
}
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
return new Dimension(0,0);
}
private boolean pertenece(ArrPuntosOra arr,Punto p)
{
try
{
int largo=arr.length();
PuntoOra[] vertice=new PuntoOra[largo];
for (int i = 0; i < largo; i++)
{
vertice[i]=arr.getElement(i);
}
for (int i=0;i<(vertice.length-1);i++)
{
Punto a=new Punto(
vertice[i].getX().intValue(),vertice[i].getY().intValue());
Punto b=new Punto(
vertice[i+1].getX().intValue(),vertice[i+1].getY().intValue());
if (!this.colineales(a,b,p))
{return false;}
else
{
if (a.x!=b.x)
{ return ((a.x <= p.x) && (p.x <= b.x))
||((a.x >=p.x)&&(p.x>=b.x));
}
else
{ return ((a.y <= p.y) && (p.y <= b.y))
||((a.y >=p.y)&&(p.y>=b.y));
}
}
}
return false;
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace(System.err) ;
return false;
}
}
367
Código Fuente
/**--------------------------------------------------------------*
p1,p2 linea de p1 a p2
*
p3 el punto a consultar.
*
el mouse no es tan presiso, por eso la comparación
*
no es == a "0"(exacto)
*/
private boolean colineales(Punto a,Punto b,Punto c)
{
return (Math.abs((a.x * b.y) - (a.y * b.x) + (a.y * c.x)
- (a.x * c.y) + (b.x * c.y) - (b.y*c.x))<300);
}
private boolean pertenece(GrafCentHidroOra gch,Punto p)
{
try
{
PuntoOra a=gch.getCuad().getA();
PuntoOra b=gch.getCuad().getB();
PuntoOra c=gch.getCuad().getC();
PuntoOra d=gch.getCuad().getD();
int vecX[]={a.getX().intValue(),b.getX().intValue(),
c.getX().intValue(),d.getX().intValue() };
int vecY[]={a.getY().intValue(),b.getY().intValue(),
c.getY().intValue(),d.getY().intValue() };
Poligono pol=new Poligono(vecX,vecY,4);
if (pol.pertenece(p))
{return true;}
else
if (pertenece(gch.getPl1().getLospuntos(),p)){return true;}
else
if (pertenece(gch.getPl2().getLospuntos(),p)){return true;}
return false;
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace(System.err) ;
return false;
}
}
368
Código Fuente
/************************************************************
* Entrega Verdadero si el punto pasado por parametro
* percenece a la figura, sino retorna falso.
*
*/
public boolean pertenece(Punto p)
{
try
{
boolean resp=false;
if((graf!=null)&&(graf.getTipo()!=null))
{
switch (graf.getTipo().intValue())
{
case 1:
resp=pertenece(graf.getGfl().getPl(),p);
break;
case 2:
resp=pertenece(graf.getGch(),p);
break;
}
}
return resp;
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
err.printStackTrace(System.err) ;
return false;
}
}
/**
* Indica si el tipo de flujo no cumple con las condiciones impuestas
*/
private boolean alertaFlujo()
{
try
{
FlujoOra flujo=this.getValue();
int tipoFlujo=flujo.getTipo().intValue();
int tipoExtrac;
try
{tipoExtrac =flujo.getEx().getTipo().intValue();}
catch (NullPointerException ex)
{tipoExtrac=-1;}
int tipoApex;
try
{tipoApex=flujo.getApex().getTipo().intValue();}
catch (NullPointerException ex)
{ tipoApex=-1;}
if((tipoFlujo==2)&&(tipoExtrac==1))
369
Código Fuente
{
ArrCaudalesOra caudales=flujo.getEx().getCa().getCaudales();
ArrCaudalesOra caudalEx=
flujo.getEx().getCa().getCaudalDeExtrac();
for(int i=1;i<=6;i++)
{
//si algun valor de caudales, es menor que el caudal de
//extracción.
if(caudales.getcaudal(new BigDecimal(i)).compareTo(
caudalEx.getcaudal(new BigDecimal(i)))==-1)
{ return true;}
}
}
else
{
if((tipoFlujo==3)&&(tipoApex==3))
{
ArrCaudalesOra cau=flujo.getApex().getCh().getCaudales();
double caudal;
double caudalMinimoGeneracion=
flujo.getApex().getCh().getCaudalMin().doubleValue();
for(int i=1;i<=6;i++)
{
caudal=cau.getcaudal(new BigDecimal(i)).doubleValue();
if (caudal<caudalMinimoGeneracion)
{ return true; }
}
}
}
}
}
catch (Exception ex)
{
JOptionPane.showMessageDialog(null,"error en flujo: "+
ex.getMessage());
}
return false;
}
370
Código Fuente
C.4.4.6 Clase: GuiNodo
package objcuenca;
import
import
import
import
import
import
import
objcuenca.*;
java.awt.Dimension;
javax.swing.JOptionPane;
java.sql.SQLException;
java.math.*;
cuencamaule.frmNodo;
figuras.*;
public class GuiNodo extends NodoOraRef implements Graficable
{
private int zoom=100;
private ElipseOra graf;
private String Codigo;
private frmNodo frm;
public GuiNodo()
{
}
//Carga la figura que reprecenta al nodo localmente
public void loadFigura()
{
try
{
//Como vamos a leer la figura desde la base de datos,
//debemos ajustarla
//al valor del zoom actual. Para esto guardo el zoom.
int zoomAct=zoom;
NodoOra no=this.getValue();
//la figura almacenada en la base de datos, esta al 100%
zoom=100;
graf=no.getGraf().getElip();
Codigo=no.getCodigo();
// restauro el valor del zoom, y se ajusta la figura
//que estaba al100%
setZoom(zoomAct);
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
//
implementacion metodos de la interfaz Graficable
public void setZoom(int zoom)
{
try
{
PuntoOra c=graf.getCentro();
371
Código Fuente
double
double
double
double
alto = graf.getAlto().doubleValue() ;
ancho = graf.getAncho().doubleValue() ;
X = c.getX().doubleValue()
;
Y = c.getY().doubleValue() ;
int actual=getZoom();
X=(X * zoom)/actual;
Y=(Y * zoom)/actual;
ancho=(ancho * zoom)/actual;
alto =(alto * zoom)/actual;
c.setX(new BigDecimal(X));
c.setY(new BigDecimal(Y));
graf.setCentro(c) ;
graf.setAlto(new BigDecimal(alto)) ;
graf.setAncho(new BigDecimal(ancho));
this.zoom=zoom;
}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
/**********************************************************
* Entrega el Zoom actual
*
*/
public int getZoom()
{
return zoom;
}
/***********************************************************
* Dibuja una elipse que reprecenta al nodo
*
*/
public void dibujar(Dibujante d)
{
try
{
d.drawElipse(graf);
int an=graf.getAncho().intValue() ;
int al=graf.getAlto().intValue() ;
int x=graf.getCentro().getX().intValue() ;
int y=graf.getCentro().getY().intValue() ;
x-=an/2;
y-=al/2;
int tamfuente=an*10/44;
if(Codigo.length() >0)
{
d.drawCenteredString(Codigo ,x,y,an, al,tamfuente);
372
Código Fuente
}
}
catch (Exception err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
/***********************************************************
* Despliega el dialogo para modificar los atributos del
* nodo
*
*/
public void dlgAtributos()
{
try
{
PuntoOra centro=graf.getCentro();
frm=new frmNodo(this);
frm.setLocation(centro.getX().intValue(),
centro.getY().intValue());
frm.pack() ;
frm.show() ;
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
}
}
/************************************************************
* Entrega la dimencion minima para el contenedor
* del nodo
*
*/
public Dimension dimensionMinima()
{
try
{
int x=graf.getCentro().getX().intValue()+
(graf.getAncho().intValue()/2);
int y=graf.getCentro().getY().intValue()+
(graf.getAlto().intValue()/2);
return (new Dimension(x,y));
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
return null;
}
}
373
Código Fuente
/************************************************************
* Entrega Verdadero si el punto pasado por parametro
* percenece a la elipse o falso si no pertenece.
*
*/
public boolean pertenece(Punto p)
{
try
{
PuntoOra centro=graf.getCentro() ;
Punto c=new
Punto(centro.getX().intValue(),centro.getY().intValue());
int an=graf.getAncho().intValue() /2;
int al=graf.getAlto().intValue() /2;
if ((((Math.pow((p.x-c.x),2))/(Math.pow(an,2)))+
((Math.pow((p.y-c.y),2))/(Math.pow(al,2))))<=1)
{return true;}
else
{return false;}
}
catch (SQLException err)
{
JOptionPane.showMessageDialog(null,err.getMessage());
return false;
}
}
}
374
Bibliografía
Bibliografía
[1] Carlos Batini, Stefano Ceri, Shamkant B. Navathe. Diseño conceptual de Bases de
datos, un enfoque de entidades-interrelaciones. Addison-Wesley/Diaz de Santos
1994
[2] Elisa Bertino, Lorenzo Martino. Sistemas de bases de datos orientadas a objetos,
conceptos y arquitecturas. Addison-Wesley/Diaz de Santos, 1995
[3] Luis
A.
Lobos,
Mauricio
J.
Cardemil,
Paola
M.
Terrazas.
“Diseño
e
Implementación de una Base de datos Objeto Relacional”. En: Actas del XIX
International Conference of the Chilean Computer Science Society, VII Encuentro
Chileno de computación, I congreso Chileno de Educación superior en
computación III Workshop Chileno en sistemas Distribuídos, Campeonato
Sudamericano de Programación ACM-Sede Chile. Talca – Chile, noviembre, 1999.
[4] Grady Booch. Análisis y Diseño Orientado a Objetos con Aplicaciones. AddisonWesley/Diaz de Santos, 1996
[5] Timothy Budd.
Introducción a la Programación orientada a Objeto.
Addison-
Wesley Iberoamericana, 1994.
[6] Paul Dorsey, Joseph R. Hudicka. Oracle 8. Diseño de Bases de datos con UML.
Osborne McGraw-Hill 1999.
[7] Andrew Eisenberg, Jim Melton. “Standars In Practice”. En
la revista Sigmod
Record(http://www.acm.org/sigmod/record/) volumen 27 número 3, septiembre
de 1998.
[8] Andrew Eisenberg, Jim Melton. “SQL:1999, formerly know as SQL3”. En la revista
Sigmod Record(http://www.acm.org/sigmod/record/) volumen 28 número 1,
marzo de 1999.
[9] Andrew Eisenberg, Jim Melton. “SQL Standardization: the Next Steps”. En
revista
Sigmod
Record(http://www.acm.org/sigmod/record/)
volumen
la
29
número 1, marzo del 2000.
[10] Ramez Elmasri, Shamkant B. Navathe. Sistemas de bases de datos, conceptos
fundamentales. Addison-Wesley Iberoamericana, 1997.
[11] Craig Larman.
Applying UML and patterns: an introduction to object-oriented
analysis and design. Prentice Hall 1998
[12] Patrick Naughton. Manual de Java. Osborne/McGraw-Hill, 1996
[13] Mario
Piattini.
“SABD
Orientados
a
Objetos”.
En:
revista
algoritmo
http://www.algoritmodigital.com, abril de 1995
[14] Mario Piattini. “El futuro de las Bases de Datos”. En: Tutorial del XIX International
376
Bibliografía
Conference of the Chilean Computer Science Society, VII Encuentro Chileno de
computación, I congreso Chileno de Educación superior en computación III
Workshop Chileno en sistemas Distribuídos, Campeonato Sudamericano de
Programación ACM-Sede Chile. Talca – Chile, noviembre, 1999.
[15] Mario Piattini.
“SQL3: Futuro estándar de bases de datos (I)”.
En: revista
algoritmo http://www.algoritmodigital.com, Octubre de 1995
[16] Mario Piattini.
“SQL3: Futuro estándar de bases de datos (II)”.
En: revista
algoritmo http://www.algoritmodigital.com, Noviembre de 1995
[17] Mario Piattini.
“SQL3: Futuro estándar de bases de datos (y III)”.
En: revista
algoritmo http://www.algoritmodigital.com, Diciembre de 1995
[18] Mario Piattini. “SQL/MM:Estándar para bases de datos multimedia”. En: revista
algoritmo http://www.algoritmodigital.com, Marzo de 1996
[19] Mario Piattini. “ODMG-93. El otro estándar para SABD Orientados a Objeto”. En:
revista algoritmo http://www.algoritmodigital.com, Abril de 1996.
[20] Roger S. Pressman. Ingeniería del Software un enfoque práctico, cuarta edición.
McGraw-Hill 1998.
[21] Antonio Quirós. “La persistencia de los objetos: un principio de la OOP (I)”. En:
revista algoritmo http://www.algoritmodigital.com
[22] Antonio Quirós. “La persistencia de los objetos: un principio de la OOP (II)”. En:
revista algoritmo http://www.algoritmodigital.com
[23] Carlos A. Sabino. Cómo hacer una tesis y toda clase de escritos, edición
ampliada. Editorial Lumen Hvmanitas, 1998
[24] Jeffrey Ulman. A First Course in Database System. Prentice Hall 1997
[25] ANSI
X3H2-99-462/WG3:SAF-003,
(ANSI/ISO
Working
Draft)
Framework
(SQL/Framework), agosto 1999. En: ftp://jerry.ece.umassd.edu/SC32/WG3
[26] ANSI
X3H2-99-463/WG3:SAF-004,
(ANSI/ISO
Working
Draft)
Foundation
(SQL/Foundation), agosto 1999. En: ftp://jerry.ece.umassd.edu/SC32/WG3
[27] Rational Software et al.
“UML Notation Guide” en UML resource Center de
Rational Software. En: http://www.rational.com/uml/index.jsp
[28] Gilberto Gutiérrez R. “Modelamiento de Sistemas de Información Geográfica bajo
un enfoque de Orientación a Objetos. Tesis para optar al grado de Magíster en
Ciencias de la Computación de la Universidad de Chile.
[29] Enrique Kaliski y Luis Arrau. “Apuntes del curso de capacitación en modelación
hidrológica”.
Documento perteneciente al la Dirección General de Aguas del
Ministerio de Obras Públicas de Chile.
377
Bibliografía
[30] Oracle. “Oracle 8i Applications Developer’s Guide – Fundamentts”. Número del
documento A68003-01 en: http://technet.Oracle.com/docs
[31] Oracle.
“Oracle 8i Concepts”.
Número del documento A67781-01 en:
http://technet.Oracle.com/docs
[32] Oracle. “Oracle 8i PL/SQL User’s Guide and Reference”. Número del documento
A67842-01 en : http://technet.Oracle.com/docs
[33] Oracle. “Oracle 8i Java Developer’s Guide”. Número del documento A64681-01
en : http://technet.Oracle.com/docs
[34] Oracle. “Oracle 8i Jpublisher User’s Guide”. Número del documento A68027-01
en: http://technet.Oracle.com/docs
[35] Oracle . “Oracle 8i Spatial. User’s Guide and reference”. Número del documento
A67295-01 en: http://technet.Oracle.com/docs
[36] Oracle.
“Oracle8i SQLJ Developer’s Guide and Reference”.
Número del
documento A64684-01 en: http://technet.Oracle.com/docs
[37] Rational Software et al.
“UML Summary” en UML resource Center de Rational
Software. En: http://www.rational.com/uml/index.jsp
[38] Rational Software et al. “UML Semantics” en UML resource Center de Rational
Software. En: http://www.rational.com/uml/index.jsp
[39] James Rumbaugh, Ivar Jacobson, Grady Booch.
El Lenguaje Unificado de
Modelado. Manual de referencia. Addison Wesley, 2000.
[40] Mario Piattini. “El futuro de las bases de datos(I). Evolución y nuevos retos”. En:
revista algoritmo http://www.algoritmodigital.com, abril de 1997.
[41] Oracle.
“Oracle8i SQL Reference”.
Número del documento A67779-01 en:
http://technet.Oracle.com/docs
[42] Oracle.
“Java Stored Procedures Developer’s Guide”.
Número del documento
A64686-01 en: http://technet.Oracle.com/docs
[43] Oracle.
“Oracle8i JDBC Developer’s Guide and Reference”.
Número del
documento A64685-01 en: http://technet.Oracle.com/docs
[44] Oracle.
“Oracle Call Interface Programer’s Guide”.
Número del documento
A76975-01 en: http://technet.Oracle.com/docs
[45] Martin Fowler. UML Gota A Gota. Editorial Addison Wesley Longman de México,
1999
[46] Jim Melton, Alan R. Simon.
SQL:1999 Understanding Relational Language
Components. Morgan Kaufmann Publishers 2001
[47] ANSI X3H2-99-269/WG3:RTM-006, (ANSI-ISO Working Draft) Persistent Stored
378
Bibliografía
Modules (SQL/PSM), agosto 1999. En:
ftp://sqlstandards.org/SC32/WG3/Progression_Documents/Informal_working_drafts/wdpsm-1999-07.pdf
[48] ISO
WG3:YYJ-007/H2-2001-144,
(ISO-ANSI
Working
Draft)
Temporal
(SQL/Temporal), Mayo 2001. En:
http://www.jtc1sc32.org/sc32/jtc1sc32.nsf/Attachments/5A5731749C3013238
8256A5B0044557A/$FILE/32N0651.PDF
[49] ISO
WG3:YYJ-012/H2-2001-149,
(ISO-ANSI
Working
Draft)
XML-Related
Specifications (SQL/XML), Mayo 2001. En :
ftp://sqlstandards.org/SC32/WG3/Progression_Documents/Informal_working_dr
afts/wd-xml-2001-06.pdf
379
Descargar