Download Implementación de código

Document related concepts
no text concepts found
Transcript
Implementación de código
Siguiendo las especificaciones del diseño realizado previamente, se ha implementado la
aplicación sin muchas dificultades en el entorno de desarrollo JDeveloper.
A la hora de hacer referencia a instrucciones del programa, sólo se copiarán trozos de
esas instrucciones que sean relevantes, comentarios y declaraciones de variables
quedarán excluidos a no ser que sean de vital importancia.
Capa de Gestion de Datos
El principal escollo al comienzo de la implementación fue establecer la conexión con la
base de datos MySQL. Tal y como se definía en el diseño, se debía de crear un objeto
GestorBD que controlase todas las transacciones con la base de datos (de ahora en
adelante BD), para ello utilizamos un conector proporcionado por MySQL (librería
mysql-connector-java-3.0.16-ga-bin.jar), que como su propio nombre indica, hacía
posible la comunicación entre un programa Java y la base de datos. Tras configurar el
JDeveloper para que incorporase la librería mencionada, ya estabamos en condiciones
de hacer una consulta SQL a la BD.
Las dos instrucciones que aparecen a continuación, son obligatorias para importar las
librerías necesarias a la hora de compilar el GestorBD:
import java.sql.*;
import com.mysql.jdbc.Driver;
Por eficiencia hemos decidido que la clase GestorBD sea una MAE, de este modo se
aprovecharán recursos en la máquina servidor, esto se puede observar en que la
constructora no es accesible desde otras clases:
private static GestorBD Gestorbd = new GestorBD();
private GestorBD() {
inicializarConexionBD();
}
public static GestorBD obtGestorBD(){
return Gestorbd;
}
El método inicializarConexionBD() configura los parámetros necesarios para establecer
la conexión con la BD, este método contiene esencialmente:
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection myCon = DriverManager.getConnection(
"jdbc:mysql://localhost/isodb",
"root","iso");
A parte de estos elementos citados, hemos tenido que crear dos métodos que ejecuten
sentencias SQL. Hemos decidido hacer dos porque creíamos necesario diferenciar entre
consultas y modificación/creación/borrado de datos, por ello implementamos los
siguientes métodos:
public Vector consulta( String c)
public boolean actualizacion( String c)
En el primer método, hacemos sólo consultas, por lo cual esperamos un resultado que
tendremos que devolver en un objeto de la clase Vector. Esta clase de Java es muy útil a
la hora de gestionar un número indeterminado de elementos y como se pretende dar
servicio a varias clases que realicen distintas consultas, cumple con los requisitos de
variabilidad. Por otra parte, el segundo método sólo realiza una acción y devuelve si esa
acción se ha desarrollado correctamente o no. A ambos métodos les pasamos un
parámetro tipo String que contiene la sentencia SQL literal.
Para hacer una consulta en la base de datos debemos utilizar las siguientes
instrucciones, que devolverán un objeto tipo ResulSet
//establece la comunicación con la base de datos
myStmt = myCon.createStatement();
//ejecutamos la sentencia SQL que tenemos en la variable c
ResultSet result = myStmt.executeQuery(c);
//finalizamos la transacción
…
//pasamos al siguiente elemento del ResulSet
result.next();
Estos resultados serán tratados y insertados en un “Vector”.
Para realizar una modificación cambiaría el método del objeto Statement (myStmt)
boolean result = myStmt.executeUpdate(c);
Si todo fue bien en la actualización realizamos un commit, si hubo algún error se hará
un rollback para que deshaga la transacción.
Esta es la implementación de la capa de datos y sobre este gestor se van a apoyar para
recibir servicios el resto de gestores de la capa de dominio de la aplicación
(GestorPases, GestorPeliculas, GestorGradoOcupación, y los que no están
implementados por ser esta una versión prototipo también lo utilizarían).
Capa de Dominio
La capa de dominio contiene a los gestores que se alojarán en el servidor, dicho servidor
puede estar en cualquier parte de una red TCP/IP, RMI es el encargado de dar soporte
para esta función de aplicación distribuida y esencialmente necesitamos estas librerías:
//librerías para la clase servidora
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
//librerías para la interfaz de la clase servidora
import java.rmi.Remote;
import java.rmi.RemoteException;
La clase servidora (por ejemplo GestorPeliculas) debe extender al objeto
UnicastRemoteObject e implementar a su interfaz ( IGestorPeliculas):
public class GestorPeliculas extends UnicastRemoteObject implements
IGestorPeliculas
Por otra parte, la interfaz debe extender el objeto Remote, esta interfaz contendrá los
métodos públicos de la clase servidora que darán servicio a los objetos del cliente:
public interface IGestorPeliculas extends Remote
En la clase servidora, hemos implementado la siguiente constructora, q hace una
llamada a su clase “super”, es decir al objeto UnicastRemoteObject, que es necesario
para utilizar RMI:
public GestorPeliculas() throws RemoteException {
super();
}
Dado que en la clase servidora y cliente se utilizan otros objetos, a estos se les debe dar
un tratamiento especial para que funcionen con RMI, a parte de contener los atributos y
métodos propios debe implementar a Serializable:
public class Pelicula implements java.io.Serializable
La clase servidora por si sola no se puede poner a ofrecer servicios, así que necesitamos
otra clase que lance todos los servicios asociados a nuestro servidor. Como la mayor
parte del código es importante vamos a ver su contenido:
package Festival;
import java.util.*;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class LanzaServidor
{
public static void main(String[] args)
{
//damos nombre a nuestros gestores que van a dar servicios
String nombreGestorPeliculas = "GestorPeliculas";
String nombreGestorPase = "GestorPase";
String nombreGestorGradoOcupacion = "GestorGradoOcupacion";
//aplicamos la política de seguridad
System.setSecurityManager(new RMISecurityManager());
try { //creamos los gestores q dan servicios
GestorPeliculas gPe = GestorPeliculas.obtGestorPeliculas();
GestorPase gPa = GestorPase.obtGestorPase();
GestorGradoOcupacion gGO = new GestorGradoOcupacion();
try {
java.rmi.registry.LocateRegistry.createRegistry(1099); // Equivalente a lanzar
RMIREGISTRY
} catch (Exception e) {System.out.println(e.toString()+"\nEl rmiregistry ya estaba
lanzado");}
// Registrar el servicio remoto, asociamos el nombre con el servicio
Naming.rebind(nombreGestorPeliculas,gPe);
Naming.rebind(nombreGestorPase,gPa);
Naming.rebind(nombreGestorGradoOcupacion,gGO);
System.out.println("Servidor lanzado.");
}catch (Exception e){System.err.println("Error lanzando servidor:" +
e.getMessage());
e.printStackTrace();}
}
}
Una vez definidos todos los elementos necesarios para implementar la tecnología RMI
en el servidor, vamos a comentar instrucciones y métodos básicos implementados.
Como hemos dicho antes, un gestor de la capa de dominio, hace uso del gestor de la
BD, pero al ser una MAE no puede hacerlo por medio de una constructora si no así:
GestorBD gBD = GestorBD.obtGestorBD();
Aquí detallamos los métodos implementados con sus principales operaciones:
/**
* método que a partir de un parámetro Película devuelve una
* lista de Películas que /cumplen los requisitos establecidos
* por los campos que tiene Película no vacíos.
*/
public Pelicula[] buscarPeliculas(Pelicula p)
//construcción de la sentencia SQL
String s = "SELECT * FROM `Pelicula` p WHERE true ";
if (titulo.compareTo("")!=0) s = s + " and titulo = "+"'"+titulo+"'";
…
//envío al gestor de la BD de la “consulta” SQL y nos devuelve un Vector
vec = gBD.consulta(s);
/**
* Método que crea una pelicula si el boolean crear es true
* y actualiza la pelicula en caso de ser false
*/
public boolean crearPelicula(Pelicula p, boolean crear)
…
//en b obtenemos si se ha realizado correctamente la actualización
b = gBD.actualizacion(s);
//método que borra una película, no se comprueba nada, de eso
//se encarga la capa de presentación
public boolean borrarPelicula(Pelicula p)
Capa de Presentación
En la capa de presentación, también hay que definir parámetros para que RMI pueda
funcionar. Primero debemos importar en el código del cliente (buscarPelicula) librerías
de RMI, pero para que obtengamos servicios de un servidor habrá que saber primero
donde está ese servidor, para ello hemos creado un objeto IPServidor, que nos devolverá
la dirección IP correspondiente al servidor que hayamos introducido nosotros al
arrancar la aplicación, o bien la dirección local si no se ha introducido ninguna
dirección. Con este dato (IP Servidor) ya podemos definir los servicios que vamos a
tomar de nuestro servidor:
//Construimos el acceso al servidor y su gestor específico,
// por ejemplo: //127.0.0.1/GestorPeliculas
String nombrePe="//"+IPServidor.obtIPS().getIP()+"/GestorPeliculas";
//Definición de la politica de seguridad
System.setSecurityManager(new RMISecurityManager());
//variables para acceder a los gestores de la capa de dominio
gp = (IGestorPeliculas)(Naming.lookup(nombrePe));
A la hora de crear la capa de presentación, hemos utilizado JDeveloper que facilita
enormemente la creación de Frames, estos objetos son las interfaces con las que actuará
el usuario, por eso todas las clases de la capa de presentación extienden a JFrame (la J
es de Java).
Vamos a seguir utilizando la gestión de películas para mostrar algunos ejemplos a la
hora de invocar a un método del servidor, como veremos, únicamente hay que hacer
referencia a las variables creadas con “Naming.lookup(…)”
//al pulsar el botón buscarPelicula, se ejecuta este método
private void buscarPelicula_actionPerformed(ActionEvent e){
…
//accedemos al método buscarPeliculas del servidor GestorPeliculas
//nos devuelve un array de Películas con los resultados
laTabla = gp.buscarPeliculas(laPeli);
Para controlar la concurrencia, hemos dicho que en vez de hacerlo en la base de datos,
lo vamos a hacer en esta capa, por una sencilla razón, el control de concurrencia en la
BD con las tablas inodbd era bastante complicado y aunque se intentó utilizar esta
tecnología, optamos al final por hacer algo más sencillo pero igual de efectivo. El
algoritmo es el siguiente:
Si (seleccionamos una película) entonces
Creamos una película temporal con los datos originales
Si (pulsamos sobre actualizar) entonces
Hacemos consulta de la película temporal
Si existe la película temporal en la BD entonces
Se puede actualizar con los datos nuevos
Si no sacar mensaje de error
Tal y como se exige en la captura de requerimientos, se debía pedir una confirmación al
usuario en el momento que este eligiese borrar una película (y pase), para ello hemos
delegado la responsabilidad de borrar en la interfaz que pide esta confirmación (objeto
Mensaje), esto es así porque no nos podíamos quedar esperando a que el usuario se
decantase por una u otra opción bloqueando la interfaz, y no es que no se pudiese,
simplemente fue una elección de diseño. Como este objeto debía servir para lo mismo a
pases y películas, creamos dos constructoras, también se debía comprobar si la película
que se pasaba como parámetro, tenía pases asignados.
public class Mensaje extends JFrame implements java.io.Serializable{
…
//si pulsamos en el botón de aceptar y estamos borrando una película
listaPases=gPase.buscarPase(laPeli,new Sala("",""), new
Pase("","","","","","","","","","",""));
//si la película elegida no tiene pases, la borramos
if(listaPases.length==0){
b= gp.borrarPelicula(laPeli);
}
else { //si tiene pases, los mostramos al usuario
GestionPases gestionPase=new GestionPases(new
Pase("","","","","","","","","",laPeli.getTitulo(),""));
b=false;
}
Como apoyo a todas las clases, nos valemos del objeto “Aviso” para mostrar mensajes
al usuario, también se utiliza RPases que contiene más datos de los que tiene que tener
un pase para poder visualizarlos y no tener que estar haciendo consultas
constantemente.
Para la identificación del usuario teníamos pensado utilizar la BD, pero por falta de
tiempo sólo lo comprobamos en local por medio de la clase Login
Según el usuario identificado, deshabilitamos unos botones u otros, por medio del
parámetro que le pasa Logina a PanelInicial.
Con estas explicaciones se ha tratado de mostrar el grueso de la implementación,
aunque puede que queden otros casos de uso por explicar, son similares a lo aquí
expuesto. La entrega al cliente también incluye los ficheros fuente de la aplicación, por
si se quiere entrar en detalle de algún trozo de código. También se ha de considerar que
este era un prototipo de aplicación y con una funcionalidad limitada y en algunos casos
modificada, por lo cual puede que haya funciones implementadas que no se hayan
utilizado (ie: cerrarConexiónBD( )) pero que en una fases más avanzadas puede que
tengan alguna utilidad.
PRUEBAS
Para realizar las pruebas hemos seguido la secuencia de acciones que cada uno de los
actores puede realizar.
Componente a probar:
Entrada al sistema local
Datos de entrada:
operador / iso
Estado del componente:
Mostrando pantalla de login
Información de contexto:
Se ha arrancado la aplicación cliente y servidor corriendo
Resultado esperado:
Muestra el Menú Principal únicamente con el botón de
Gestionar películas habilitado
Componente a probar:
Entrada al sistema local
Datos de entrada:
planificador / iso
Estado del componente:
Mostrando pantalla de login
Información de contexto:
Se ha arrancado la aplicación cliente y servidor corriendo
Resultado esperado:
Muestra el Menú Principal sólo con el botón de Calcular
Grado de Ocupación deshabilitado
Componente a probar:
Entrada al sistema local
Datos de entrada:
estratega / iso
Estado del componente:
Mostrando pantalla de login
Información de contexto:
Se ha arrancado la aplicación cliente y servidor corriendo
Resultado esperado:
Muestra en el Menú Principal todos los botones
Componente a probar:
Entrada al sistema local
Datos de entrada:
cualquier nombre /cualquier contraseña
Estado del componente:
Mostrando pantalla de login
Información de contexto:
Se ha arrancado la aplicación cliente y servidor corriendo
Resultado esperado:
mensaje de error diciendo que el usuario/contraseña es
incorrecto
Componente a probar:
Entrada a un sistema remoto
Datos de entrada:
Usuario valido/contraseña valida/ipservidor
Estado del componente:
Mostrando pantalla de login
Información de contexto:
Se ha arrancado la aplicación cliente en local y el servidor
corriendo en remoto
Resultado esperado:
Muestra el menú principal mostrando los botones que
correspondan
Componente a probar:
Botón Gestionar Peliculas
Datos de entrada:
hacer click en el botón Gestionar Peliculas
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Menú Principal
Resultado esperado:
Se abre la pantalla titulada Película
Componente a probar:
Botón Buscar Película
Datos de entrada:
hacer clic en el botón Buscar Película
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Pelicula
Resultado esperado:
aparecen en la tabla de la derecha las películas que
coincidan con los campos rellenables de la izquierda, si
están todos los campos vacíos, mostrará todas las películas
de la BD
Componente a probar:
Selección de Película/Pase
Datos de entrada:
hacer clic en un registro que se muestra en la tabla que
aparece a la derecha
Estado del componente:
hay algún elemento en la tabla
Información de contexto:
Se muestra Pantalla Película \ Buscar Pases \ Gestionar
Pases
Resultado esperado:
los campos de la izquierda se rellenan con los datos del
elemento seleccionado
Componente a probar:
Botón Crear Película
Datos de entrada:
hacer clic en el botón Crear Película
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Pelicula
Resultado esperado:
si se ha podido crear la película aparecerá un mensaje
diciendo que ha podido crear la película, en caso contrario
aparecerá un mensaje diciendo que no se ha podido crear la
pelicula
Componente a probar:
botón Actualizar Película
Datos de entrada:
hacer clic en el botón Actualizar Película
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Película y hay una película
seleccionada
Resultado esperado:
Muestra un mensaje del resultado de la operación, si otro
usuario ha editado esa película no la actualizará y se lo
mostrará al usuario
Componente a probar:
botón Borrar Película
Datos de entrada:
hacer click en el botón Borrar película
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Película y hay una película
seleccionada
Resultado esperado:
se pide una confirmación al usuario, si se pulsa aceptar y la
película tiene pases, nos muestra los pases de la película, si
no los tiene muestra un mensaje de borrado
Componente a probar:
botón limpiar campos
Datos de entrada:
hacer clic en el botón Limpiar Campos
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Película / Buscar Pases / Gestionar
Planificación
Resultado esperado:
todos los campos editables de la izquierda se ponen en
blanco
Componente a probar:
botón Cerrar
Datos de entrada:
hacer clic en el botón de Cerrar
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Película / Buscar Pases / Gestionar
Planificación
Resultado esperado:
se cierra la Pantalla activa
Componente a probar:
botón Gestionar Pases
Datos de entrada:
hacer clic en el botón Gestionar Pases
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Inicio
Resultado esperado:
se abre la Pantalla Buscar Pases
Componente a probar:
botón Buscar Pase
Datos de entrada:
hacer clic en el botón Buscar Pases
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Buscar Pases / Gestionar Planificación
Resultado esperado:
aparecen en la tabla de la derecha los pases que coincidan
con los campos editables de la izquierda, si están todos los
campos vacíos, mostrará todos los pases de la BD
Componente a probar:
Botón Seleccionar Pase
Datos de entrada:
hacer clic en Seleccionar Pase
Estado del componente:
botón habilitado
Información de contexto:
Se muestra pantalla Buscar Pases y hay un pase
seleccionado en los campos editables de la izquierda
Resultado esperado:
Muestra la pantalla Gestionar Planificación con los datos
mínimos cargados en los campos editables.
Componente a probar:
botón Gestionar Planificación
Datos de entrada:
hacer clic en el botón Gestionar Planificación
Estado del componente:
botón habilitado
Información de contexto:
Muestra pantalla Inicio
Resultado esperado:
Muestra la pantalla Gestionar Planificación
Componente a probar:
Botón Crear Pase
Datos de entrada:
hacer clic en el botón Crear Pase
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Gestionar Planificación
Resultado esperado:
si se ha podido crear el pase aparecerá un mensaje diciendo
que ha podido crear la película, en caso contrario aparecerá
un mensaje diciendo que no se ha podido crear
Componente a probar:
botón Actualizar Pase
Datos de entrada:
hacer clic en el botón Actualizar Pase
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Gestionar Planificación y hay un pase
seleccionado
Resultado esperado:
Muestra un mensaje del resultado de la operación, si otro
usuario ha editado esa película no la actualizará y se lo
mostrará al usuario
Componente a probar:
botón Borrar Pase
Datos de entrada:
hacer clic en el botón Borrar Pase
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Gestionar Planificación y hay un pase
seleccionado
Resultado esperado:
se pide una confirmación al usuario, si se pulsa aceptar
borra el pase y si cancela, se deja el pase como estaba. En el
primer caso obtenemos un mensaje con el resultado de la
operación de borrado
Componente a probar:
botón Grado de Ocupación
Datos de entrada:
hacer clic en el botón Grado de Ocupación
Estado del componente:
botón habilitado
Información de contexto:
Se muestra Pantalla Inicio
Resultado esperado:
se abre la Grado de Ocupación
Componente a probar:
seleccionar Tipo de dato
Datos de entrada:
hacer clic en uno de los tipos de dato disponibles
Estado del componente:
sólo un botón seleccionado
Información de contexto:
Se muestra Pantalla Grado de ocupación
Resultado esperado:
el tipo de dato quedará seleccionado
Componente a probar:
Botón Calcular
Datos de entrada:
hacer clic en Calcular
Estado del componente:
botón habilitado
Información de contexto:
Se muestra pantalla Grado de ocupación, el campo Fecha
debe estar rellenado según se informa y debe haber en el
campo Dato un dato que corresponda con el tipo de dato
seleccionado
Resultado esperado:
Muestra el grado de ocupación para ese dato hasta la fecha
introducida.
Related documents