Download 3 de SEPTIEMBRE de 2004

Document related concepts
no text concepts found
Transcript
INGENIERÍA DEL SOFTWARE. 4º ING. INFORMÁTICA (UPV/EHU)
3 de SEPTIEMBRE de 2004
NOMBRE:
1) (0,25 ptos.) (Tiempo: 5 minutos) ¿Qué es la ingeniería del software ?
2) (0,25 ptos.) (Tiempo estimado: 5 minutos) ¿Qué es el CMM?
GRUPO:
3) (1 pto.) (Tiempo estimado: 20 minutos) Dado el caso de uso ENTRAR EN EL SISTEMA,
y el siguiente caso de prueba
Entrada: usuario “correcto” password “acertado” con 5 intentos previos fallidos
Salida: NO dar paso y el número de intentos en la tabla
USUARIO(cuenta,passord,numIntentos) para “correcto” es 5
Escribir un componente de prueba para poder probar al menos el caso de prueba anterior,
teniendo en cuenta que disponemos de las siguientes clases.
NOTA: Si se usa alguna otra clase auxiliar, describirla usando UML.
Presentacion
-logNeg : InterfaceLogicaNegocio
«interface»
InterfaceLogicaNegocio
+entradaSistema(in cuenta : string, in password : string) : Boolean
«subsystem»
java.rmi
EntradaSistemaRemotoBD
+entradaSistema(in cuenta : string, in password : string) : Boolean
«subsystem»
java.sql
SOLUCIÓN:
public class ComponentePruebaEntrSistema {
InterfaceLogicaNegocio ln; OperacionesParaPruebas lp;
public static void main(String[] args) {
ln = java.rmi.Naming.lookup(“rmi://MAQ:PUERTO/nombreServ”);
lp.aniadirUsuario(“correcto”,“acertado”,5);
boolean b = ln.entradaSistema(“correcto”,“acertado”);
if (b) System.out.println(“Error CPx: Permite entrada”);
else {int j = lp.comprobarUsuario(“correcto”,“acertado”);
// Dev. Nº intentos
if (j!=5) System.out.println(“Error CPx: nº int no es 5”);
else System.out.println(“CPx correcto”);} }
donde se usa la clase:
OperacionesParaPruebas
+aniadirUsuario(in cuenta : string, in password : string, in numInt : int)
+comprobarUsuario(in cuenta : string, in password : string) : Boolean
4) (2,5 ptos.) (Tiempo estimado: 30 minutos) El caso de uso APUNTAR SESIÓN DE
TRABAJO sirve para registrar en el sistema el número de minutos trabajados por una
persona (identificada con el DNI) en una determinada fecha.
A continuación se presenta gran parte de la implementación de dicho caso de uso, así como
un esquema en UML de las clases, componentes, paquetes y relaciones de dependencia y
herencia entre ellos. SE PIDE: implementar la clase RegistrarHorasBeanEx.java, siguiendo
estrictamente el esquema UML y sin modificar absolutamente nada el código de las otras
clases que se proporcionan.
ApuntarHorasEx.jsp
RegistrarBilletesBeanEx
RegistrarHorasEx.jsp
+????()
+????()
«interface»
InterfaceRegistrarHoras
+insertar(in dni : string, in numMins : int, in fecha : Date) : int
GestorRegistrarHoras
«subsystem»
java.rmi
+insertar(in dni : string, in numMins : int, in fecha : Date) : int
«subsystem»
java.sql
Esta es la implementación del JSP ApuntarHorasEx.jsp (no se incluye el código JavaScript
para validar los datos de entrada)
<html><body>
<h2> APUNTAR SESIÓN DE TRABAJO </h2>
<form action="RegistrarHorasEx.jsp" name="formulario" method="post">
DNI: <input type="text" name="dni"> <BR>
Fecha: <input type="text" name="dia" size=1>
<select name="mes" simple>
<option value="3" selected>Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
</select>
2004<BR>
Num. de minutos: <input type="text" name="minutos" value="0"> <BR>
<input type="submit" name="enviar" value="Enviar Datos">
</form></body></html>
Esta es la implementación del JSP RegistrarHorasEx.jsp
<%@ page contentType="text/html;charset=windows-1252" import="java.util.Date"
import="java.sql.*"%>
<html><body>
<jsp:useBean id="logNegocio" class="regHoras.RegistrarHorasBeanEx"
scope="request" />
<% boolean res = logNegocio.registrarHoras(
request.getParameter("dni"),
request.getParamete r("minutos"),
request.getParameter("dia")+"/"+request.getParameter("mes")+"/04"
);
if (res) out.println("DATOS INSERTADOS CORRECTAMENTE");
else out.println("DATOS NO INSERTADOS CORRECTAMENTE POR ESTA RAZON: "+
logNegocio.getMensajeError());
%>
</body></html>
Esta es la implementación de la interfaz InterfaceRegistrarHoras.java
package regHoras;
import java.rmi.*;
public interface InterfaceRegistrarHoras extends Remote
{int insertar(String dni,String fecha, int numMins) throws RemoteException; }
Esta es la implementación de la clase GestorRegistrarHoras.java
package regHoras;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.*;
import java.sql.*;
public class GestorRegistrarHoras extends UnicastRemoteObject
implements InterfaceRegistrarHoras
{ PreparedStatement s1,s2; Connection o; ResultSet rs,rs2;
public GestorRegistrarHoras() throws RemoteException
{ try{ Class.forName("org.gjt.mm.mysql.Driver");
o=DriverManager.getConnection("jdbc:mysql://localhost/BDHorasProy");
s1=o.prepareStatement("insert into sesion(dni,fecha,numMins)
values(?,?,?)");
s2=o.prepareStatement("select * from estudiante where dni=?");
}catch (Exception ex){System.out.println("Error: "+ex.toString());}}
public int insertar(String dni,String fecha, int numMins)
throws RemoteException
{try{ s2.setString(1,dni);
rs=s2.executeQuery();
if (!rs.next()) return -1; // No existe DNI
s1.setString(1,dni);
s1.setString(2,fecha);
s1.setInt(3,numMins);
int res = s1.executeUpdate();
if (res==0) System.out.println("Error: no insertado...");
return res;
} catch (Exception e) {System.out.println("Error: "+e.toString());
return -5;}}
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try { GestorRegistrarHoras objetoServidor = new GestorRegistrarHoras();
try { java.rmi.registry.LocateRegistry.createRegistry(1099);}
catch (Exception e)
{System.out.println(e.toString()+"\nRmiregistry ya lanzado");}
Naming.rebind("//localhost:1099/registrarHoras",objetoServidor);
} catch (Exception e) {System.out.println("Error: "+e.toString());}}}
SOLUCIÓN:
package regHoras;
import java.rmi.*;
public class RegistrarHorasBeanEx
{ InterfaceRegistrarHoras logNeg;
private String err= “”;
public static String maquina= “localhost”;
public RegistrarHorasBeanEx()
{try{
logNeg = ((InterfaceRegistrarHoras)Naming.lookup("rmi://
"+maquina+":1099/registrarHoras"));
} catch(Exception e) {System.out.println("Error al conseguir la
lógica del negocio: "+e.toString());}
}
public boolean registrarHoras(String dni, String mins, String fecha)
{ try {
int res = logNeg.insertar(dni,fecha,Integer.parseInt(numMins));
if (res==-1) err = "El dni no existe";
else if (res<=0) err = "Error: no ha podido insertarse";
else err = "Datos insertados: DNI="+dni+" minutos="+mins;
return (res>0); }
catch (Exception e) {System.out.println("Error: "+e.toString());
err = "Error: no ha podido insertarse";
return false;} }
public String getMensajeError() return err; } }
5) (2 ptos.) (Tiempo estimado: 45 minutos)
Usuario
*
poneEnVenta
1
1
*
pujan
-nombre : string
-ciudad : string
-dirección : string
propietario
1*
Subasta
-precioSalida : int
-codigoArtículo : int
-propietario : Usuario
-categoria : string
*
gana
*
oferta
tiene
1
CasaDeSubastas
1
Una casa de subastas quiere realizar una aplicación para gestionar sus subastas on-line. En
la figura superior se muestra el diagrama de clases UML del sistema, donde los rombos
negros representan relaciones de agregación.
Una casa de subastas contiene un conjunto de usuarios y subastas y OJO, sólo existe una
instancia de esa clase en el sistema. Un Usuario pone en Venta una serie de subastas, y
además puede ganar otra serie de subastas. A su vez una subasta, puede tener un conjunto
de usuarios que pujan por ella. De cada subasta almacenamos el precio de salida, el código
del artículo en subasta, el propietario y la categoría a la que pertenece. De un usuario se
almacena su nombre, ciudad y dirección.
Se pide utilizando los contenedores, predicados, funciones y algortimos JGL programar las
siguientes funcionalidades:
1. En la clase Usuario, un método que devuelve las subastas que están en la misma ciudad
que su ciudad de origen.
2. En la clase CasaDeSubastas, un método que devuelva aquellos usuarios que tengan en
venta al menos una subasta.
3. En la clase CasaDeSubastas, un método que devuelva aquellos usuarios que tengan al
menos una subasta por la que haya pujado alguien.
SOLUCIÓN:
Usuario
*
poneEnVenta
1
1
*
pujan
-nombre : string
-ciudad : string
-dirección : string
propietario
1*
Subasta
-precioSalida : int
-codigoArtículo : int
-propietario : Usuario
-categoria : string
*
gana
*
oferta
tiene
1
CasaDeSubastas
1
1. En la clase Usuario, un método que devuelve las subastas que están en la misma ciudad
que su ciudad de origen.
void Container subastasMismaCiudad(){
UnaryPredicate mismaCiudad=new UnaryComposePredicate(
new BindSecondPredicate(new EqualString(),getCiudad()),
new ObtenerCiudad());
Container resultado=Filtering.select(CasaDeSubastas.oferta, mismaCiudad);
return resultado;
}
public class ObtenerCiudad implements UnaryFunction {
Object execute(Object o) {
Subasta s=(Subasta)o;
return (s.getPropieatario().getCiudad());
}
}
}
2. En la clase CasaDeSubastas, un método que devuelva aquellos usuarios que tengan en
venta al menos una subasta.
void Container visualizarUsuariosConSubastas (){
UnaryPredicate conSubastas=new UnaryComposePredicate(
new BindSecondPredicate(new GreaterNumber(),new Integer(0)),
new ObtenerSubastas());
Container resultado=Filtering.select(tiene ,conPujas);
}
public class ObtenerSubastas implements UnaryFunction {
Object execute(Object o) {
Usuario u=(Usuario)o;
return (u.getPoneEnVenta().size()); }
}
3. En la clase CasaDeSubastas, un método que devuelva aquellos usuarios que tengan al
menos una subasta por la que haya pujado alguien.
void Container UsuariosConPujas(){
UnaryPredicate conPujas=new UnaryComposePredicate(
new BindSecondPredicate(new GreaterNumber(),new Integer(0)),
new ObtenerPujas());
Container resultado=Filtering.select(tiene,conPujas);
return resultado;
}
public class ObtenerPujas implements UnaryFunction {
Object execute(Object o) {
Usuario u=(Usuario)o;
UnaryPredicate conPujas=new UnaryComposePredicate(
new BindSecondPredicate(new GreaterNumber(),new Integer(0)),
new ObtenerPujas());
Container conPujas=Filtering.select(u.getPoneEnVenta(),conPujas);
return new Integer(conPujas.size());
}
}
6) (1.5 ptos.) (Tiempo estimado: 30 minutos)
Desarrollar un componente EJB para la realización de transferencias bancarias para una
entidad bancaria. Para realizar una transfere ncia hay que seguir los siguientes pasos):
1. Conectarse (dniUsuario, password)
2. Realizar la transferencia(cuenta origen, destino y cantidad)
3. Desconectarse.
Se pide:
1. Definir las interfaces del Componente con sus correspondientes métodos
2. Implementar el Compone nte.
NOTA: Las interfaces
javax.ejb.EJBHomeObject
extienden
de
las
clases:
javax.ejb.EJBObject
y
NOTA: Tanto las claves CLAVES(usuario, password) como las CUENTAS(idCuenta,
cantidad de los usuarios, están almacenadas en la BD en sus correspondientes tablas. Los
objetos entidad que mapean estas tablas están accesibles a través los identificadores
ClavesJNDI y CuentasJNDI respectivamente.
SOLUCIÓN:
public interface Transfer extends EJBObject {
void connect(Str ing dniUser, String passwd)
void transfer(int account1, int account2, int q)
void disconnect()
}
public interface TransferHome extends EJBHomeObject {
public Transfer create() throws RemoteException, CreateException;
}
public class TransferBean implements SessionBean {
boolean isConnected;
void connect(String user, String passwd){
Properties props=System.getProperties();
// Obtener el contexto JNDI inicial (ip, posicion árbol)
InitialContext ctx=new InitialContext(props);
Object obj=ctx.lookup(“ClavesJNDI”);
// Casting
AccountHome home=(AccountHome )
PortableRemoteObject.narrow(
obj, AccountHome .class);
Object usr=home.findByPrimaryKey(user);
User usuario=(User)javax.rmi.PortableRemoteObject.narrow(
usr,User.class);
if (usuario.getPassword().equals(passwd)
isConnected=true;
}
}
void transfer(int account1, int account2, int q){
if (isConnected) {
//propiedades JNDI
Properties props=System.getProperties();
// Obtener el contexto JNDI inicial (ip, posicion árbol)
InitialContext ctx=new InitialContext(props);
Object obj=ctx.lookup(“CuentasJNDI”);
// Casting
AccountHome home=(AccountHome )
PortableRemoteObject.narrow(
obj, AccountHome .class);
Object c1=home.findByPrimaryKey(account1);
Object c2=home.findByPrimaryKey(account2);
Account account1=(Account)javax.rmi.PortableRemoteObject.narrow(
c1,Account.class);
Account account2=(Account)javax.rmi.PortableRemoteObject.narrow(
c2,Account.class);
if (c1.getBalance()>q) {
c1.withdraw(q);
c2.deposit(q);
}
}
void disconnect() {isConnected=false;}
}
7) (2 ptos.) (Tiempo estimado: 45 minutos)
La comisión de festejos de nuestro ayuntamiento nos ha encomendado la tarea de diseñar e
implementar una aplicación informática para gestión los eventos y personal involucrado en
la organización de las fiestas.
1. El ayuntamiento clasifica al personal en 3 tipos de trabajadores: peones,
organizadores de actividades y organizadores de zona. Los organizadores de
actividades tienen peones a su cargo, mientras que los organizadores de zona,
disponen de organizadores de actividades y peones.
Que patrón utilizarías para clasificar jerárquicamente al personal, sabiendo que el futuro
puedan aparecer nuevos tipos de pe rsonal (p.ej. Voluntarios).
Implementa un método que visualice para cualquier miembro del ayuntamiento, las
personas que tiene a su cargo así como cual es su categoría.
2. Sabiendo que:
a. El Programa de Fiestas esta compuesto de una serie de festejos(día, lugar,
nombre)
b. El método Printing.print(Enumeration e), imprime todos los objetos
almacenados en el enumerado.
Qué patrón utilizarías para poder imprimir el Programa de Fiestas utilizando el
método anterior suponiendo que:
1. Tienes acceso a la clase Programa de Fiestas y puedes modificar su código
2. NO puedes modificar la clase Programa de Fiestas.
Diseña e implementa la solución en ambos supuestos.
(Solucion apartado 1) Se solucionaría aplicando el patrón COMPOSITE.
Componente
*
+visualizar()
Simple
Compuesto
+visualizar()
Voluntarios
+visualizar()
Peón
+visualizar()
+visualizar()
Org. Actividades
+visualizar()
1
Org. Zona
+visualizar()
(Solución apartado 2) En apartado a al poder modificar la clase Programa de Fiestas
podemos hacer que la clase implemente la interfaz Enumeration, y así utilizando el
patrón INERFAZ poder pasar una instancia del la clase Programa de Fiestas al
método print de la clase Printing.
use
Printing
+print(Enumeration e)()
«interface»
Enumeration
+hasMoreElements()
+nextElement()
implements
«interface»
Visualizable
+visualize()
implements
ProgramaFiestas
1
Festejo
*
+hasMoreElements()
+nextElement()
+vizualize()
En el apartado b, al no poder modificar la clase Programa de Fiestas, tendremos que
utilizar un clase de ADAPTE la clase Programa de Fiestas a la interfaz
Enumeration.
use
Printing
+print(Enumeration e)()
«interface»
Enumeration
+hasMoreElements()
+nextElement()
implements
Adapter
+hasMoreElements()
+nextElement()
«interface»
Visualizable
+visualize()
implements
1
Festejo
+vizualize()
ProgramaFiestas
*
usa