Download 13 de SEPTIEMBRE de 2007

Document related concepts
no text concepts found
Transcript
INGENIERÍA DEL SOFTWARE. 4º ING. INFORMÁTICA (UPV/EHU)
13 de SEPTIEMBRE de 2007
NOMBRE:
GRUPO:
1ª PREGUNTA: ARQUITECTURAS EN 3 NIVELES) (2.5 ptos.) (Tiempo estimado: 45 minutos) A
continuación se presenta la implementación usando una arquitectura en 3 niveles físicos del caso de
uso PEDIR BILLETE que se ha utilizado durante este cuatrimestre (es exactamente el que aparecía en
la página web de la asignatura).
package ejsA3N;
import java.rmi.*;
public interface GestorBilletes extends Remote
{ public Billete getBillete(String nom) throws RemoteException; }
package ejsA3N;
import java.util.Date;
public class Billete implements java.io.Serializable
{ private int num; private String nomb; private Date fecha;
public Billete(int n,String nom){num=n; nomb=nom; fecha=new Date(); }
public int getNum(){return num;}
public String getNombre(){return nombre;}
public Date getFecha(){return fecha;} }
package ejsA3N;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.rmi.*;
public class PedirBillete extends JFrame {
JPanel jPanel1 = new JPanel(); JLabel jLabel1 = new JLabel();
JTextField jTextField1 = new JTextField();
JButton jButton1 = new JButton();
JTextArea jTextArea1 = new JTextArea();
GestorBilletes gestorBilletes; // Objeto con la lógica del negocio
public PedirBillete() {
super();
try {jbInit();} catch (Exception e) {e.printStackTrace();}}
private void jbInit() throws Exception {
this.getContentPane().setLayout(null);
this.setSize(new Dimension(400, 300));
jPanel1.setLayout(null);
jPanel1.setBounds(new Rectangle(0, 0, 392, 273));
jLabel1.setText("Nombre:");
jLabel1.setBounds(new Rectangle(54, 58, 64, 17));
jTextField1.setBounds(new Rectangle(124, 50, 163, 33));
jButton1.setText("Pedir Billete");
jButton1.setBounds(new Rectangle(103, 189, 156, 44));
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);} });
jTextArea1.setBounds(new Rectangle(88, 94, 189, 76));
this.setTitle("Pedir Billetes");
this.getContentPane().add(jPanel1, null);
jPanel1.add(jLabel1, null); jPanel1.add(jTextField1, null);
jPanel1.add(jButton1, null); jPanel1.add(jTextArea1, null); }
public void setGestorBilletes(GestorBilletes g) { gestorBilletes=g; }
void jButton1_actionPerformed(ActionEvent e) {
try{int res =
gestorBilletes.getBillete(jTextField1.getText()).getNum();
if (res<0) jTextArea1.append("Error al asignar billete");
else jTextArea1.append("Asignado. \nReferencia: "+res+"\n");
} catch (Exception er) {System.out.println("Error: "+er.toString());
jTextArea1.append("Error al asignar billete");}}
public static void main (String []arg) {
PedirBillete b = new PedirBillete();
System.setSecurityManager(new RMISecurityManager());
String servicioRemoto = "rmi://localhost:1099/gestorBilletes”;
GestorBilletes objetoRemoto;
try{objetoRemoto = (GestorBilletes)Naming.lookup(servicioRemoto);
b.setGestorBilletes(objetoRemoto); }
catch (Exception e) {System.out.println("Error: "+e.toString());}
b.setVisible(true); }}
package ejsA3N;
import java.rmi.*;
import java.sql.*;
import java.io.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
public class ServidorGestorBilletesBD extends UnicastRemoteObject
implements GestorBilletes
{
private static Connection conexion;
private static Statement sentencia;
public ServidorGestorBilletesBD() throws RemoteException{
try {Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");
conexion.setAutoCommit(false);
sentencia=conexion.createStatement(); }
catch(Exception e){System.out.println("Error:"+e.toString());}}
public Billete getBillete(String nom)
throws RemoteException {
// Devuelve billete con nº billete, -1 si no hay, -2 problemas
String pregSQL = "SELECT NUMERO FROM BILLETES"+
" WHERE ESTADO=\'LIBRE\'";
try{ ResultSet rs = sentencia.executeQuery(pregSQL);
if (rs.next()) {
String num = rs.getString("NUMERO");
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = '"+nom+
"' WHERE NUMERO="+num+" AND ESTADO='LIBRE'");
conexion.commit();
int n= Integer.parseInt(num);
if (act>0) return new Billete(n,nom); // N. bill asignado
return new Billete(-2,""); } // Otro ha OCUPADO billete
else return new Billete(-1,"");; } // No había libre
catch (SQLException e){System.out.println(e.toString());}
return new Billete(-2,""); } // Que prueben otra vez a llamar
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try { java.rmi.registry.LocateRegistry.createRegistry(numPuerto);
} catch (Exception e) {System.out.println(Rmiregistry exist");}
try { ServidorGestorBilletesBD objetoServidor =
new ServidorGestorBilletesBD();
String servicio="//localhost:1099/gestorBilletes";
Naming.rebind(servicio,objetoServidor);
} catch (Exception e){System.out.println(e.toString());}}}
Se trata de desarrollar un caso de uso complementario al anterior llamado “DEVOLVER BILLETES”
donde se puede devolver un número de billetes indicado a nombre de una persona. Además, se puede
decir si se quiere devolver EXACTAMENTE es número. En tal caso, o se devuelven todos los billetes o
ninguno. Si no, se devolverán todos los billetes que se pueda hasta el número indicado. Como resultado
se mostrará el número de billetes devuelto.
Se pide:
1) Diseñar en UML una solución para el caso de uso “DEVOLVER BILLETES” que utilice una
arquitectura física en 3 niveles.
2) Indicar TODOS LOS CAMBIOS que hay que hacer en la IMPLEMENTACIÓN con
respecto a la solución anterior del caso de uso “DEVOLVER BILLETES”. Cuando se trate de
un método nuevo hay que hacer la implementación completa del método.
SOLUCIÓN:
DevolverBilletes (es como PedirBillete)
...
GestorBilletes2 gestorBilletes;
private JTextField jTextField2 = new JTextField(); // Número de billetes a devolver
private JCheckBox jCheckBox1 = new JCheckBox();
// Indicar si “exactamente”
...
void jButton1_actionPerformed(ActionEvent e) { // Método respuesta pulsar botón
try{int res =
gestorBilletes.devolverBilletes(Integer.parseInt(jTextField2.getText()),
jTextField1.getText(),
jCheckBox1.isSelected());
jTextArea1.append("\nNum. billetes devueltos: "+res);
} catch (Exception er) {System.out.println("Error: "+er.toString());
jTextArea1.append("\nError al devolver billete");}}
GestorBilletes2:
public interface GestorBilletes2 extends Remote
{ public int devolverBilletes(int n, String nom,boolean exactamente) throws
RemoteException;}
ServidorGestorBilletesBD2 (es como ServidorGestorBilletesBD, pero con algún cambio)
public class ServidorGestorBilletesBD2
extends UnicastRemoteObject
implements GestorBilletes2
{
// ...
public int devolverBilletes(int n, String nom,boolean exactamente)
throws RemoteException {
String pregSQL = "SELECT NUMERO FROM BILLETES"+
" WHERE ESTADO='OCUPADO' AND NOMBRE='"+nom+"'";
int faltan=n;
try{
ResultSet rs = sentencia.executeQuery(pregSQL);
while (rs.next() && (faltan>0)) {
String num = rs.getString("NUMERO");
int act = sentencia2.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='LIBRE' "+
" WHERE NUMERO="+num+" AND ESTADO='OCUPADO'");
if (act>0) {
faltan--;
}
}
if (faltan==0) { conexion.commit(); return n;}
else { if (exactamente) { conexion.rollback(); return 0;}
else { conexion.commit(); return n-faltan;}}}
catch (SQLException e)
{System.out.println("Error: "+e.toString());}
return -1; // Que prueben otra vez a llamar }
2ª PREGUNTA: PRUEBAS) (1,5 ptos.) (Tiempo estimado: 15 minutos) Diseñar el siguiente caso de
prueba para el caso de uso anterior e implementar un componente de prueba en JUNIT que lo pruebe.
// OBJETIVO DEL CASO DE PRUEBA: comprobar que “si se quiere devolver un número de
billetes a nombre de una persona superior al número de billetes que tiene y no se quiere devolver
exactamente ese número, entonces deja devolver el número de billetes que tiene”
Entrada:
Condiciones de entrada:
Salida:
NOTA: Si para el componente de prueba se usa alguna otra clase auxiliar, describirla usando UML.
import junit.framework.*;
public class ComponentePruebaDevolverBilletes extends TestCase
{ public ComponentePruebaDevolverBilletes (String nombre)
{ super(nombre); }
protected void setUp() { }
protected void tearDown() { }
// assertTrue(b) falla si y solo si b es false
public static Test suite() {
return new TestSuite(ComponentePruebaDevolverBilletes.class);
public static void main(String args[]) {
junit.textui.TestRunner.run(suite()); }}
}
SOLUCIÓN:
// OBJETIVO DEL CASO DE PRUEBA: comprobar que “si se quiere devolver un número de
billetes a nombre de una persona superior al número de billetes que tiene y no se quiere devolver
exactamente ese número, entonces deja devolver el número de billetes que tiene”
Entrada: Devolver 9 billetes a nombre de “KEPA KORTA” indicando que no se desea
devolver exactamente ese número sino los que se puedan hasta 9.
Condiciones de ejecución: En la tabla BILLETES(NUMERO,ESTADO,NOMBRE) de la BD hay 6
billetes con ESTADO=’LIBRE’ y 7 billetes a nombre de KEPA KORTA
Resultado esperado: Se devuelven los 7 billetes de KEPA KORTA, quedando 13 libres y
ninguno ocupado.
public class ComponentePruebaPedirNBilletes extends TestCase
{
GestorBilletes logNeg;
OpsPruebas logPru;
public ComponentePruebaPedirNBilletes (String nombre)
{ super(nombre);
try{
logNeg = (GestorBilletes)Naming.lookup("rmi://localhost:1099/gestorBilletes");
logPru = new OpsPruebas();}
catch (Exception e) {System.out.println("Error: "+e.toString());} }}
protected void setUp() { }
protected void tearDown() { }
public void testDevolverMasBilletesQueDisponibles() {
try{
logPru.inicializarBilletes(6,7,"Kepa Korta");
int i = logNeg.devolverBilletes(9,"Kepa Korta",false);
int n = logPru.getNumBilletesLibres();
int m = logPru.getNumBilletesOcupados("Kepa Korta");
assertTrue((i==7) && (n==13) && (m==0));
}
catch (Exception e) {System.out.println("Error al llamar "+e.toString());
assertTrue(false);} }}
public static Test suite() {
return new TestSuite(ComponentePruebaPedirNBilletes.class); }
public static void main(String args[]) {
junit.textui.TestRunner.run(suite()); }}
3ª PREGUNTA: JGL (2 ptos.) (Tiempo estimado: 30 minutos1. Se desea añadir a la librería JGL,
otra nueva interfaz de "objetos funcion" (ActionObject), de tal forma que la función no devuelva
NADA, es decir,
f(x)=void
y únicamente modifique el contenido del objeto referenciado por x. Cómo definirías esta nueva
interfaz?
2. Define una clase función que implementa la interfaz de punto anterior, que para objeto de tipo
Nota(valor, calificación), rellene el campo calificación a partir del atributo valor.
3. Define un algoritmo que a partir de un contenedor JGL y un objeto función de tipo ActionObject,
aplique la función a todos los elementos del contenedor
4. Realizar un programa que cree un contenedor con Notas, rellenando su valor, y aplique la funcion
del punto 2 para rellenar su calificación
SOLUCIÓN:
1.
public interface ActionObject<T> {
void execute(T obj);
}
2.
public class RellenaNota<Nota> extends ActionObject<Nota> {
void execute(Nota n) {
if (n.getValor<5) then n.calificación="Suspenso";
else
if ( (n.getValor()>=5)|| (n.getValor()<7) )
then n.calificacion="Aprobado)……
}
3.
class Executing {
public static void executeAction(Container c, ActionObject ao){
Object o;
Enumeration e=c.elements();
while (e.hasMoreElements()){
o=e.nextElement();
ao.execute(o);
}
}
}
4.
public static void main(String args[]){
Container<Notas> notas=new SList<Notas>();
notas.add(new Nota(5));
notas.add(new Nota(7));
notas.add(new Notas(3));
----------ActionObject<Nota> ao=new RellenaNota<Nota>();
Executing.executeAction(ao, notas);
}
4ª PREGUNTA: PATRONES DE DISEÑO (2 ptos.) (Tiempo estimado: 45 minutos)
Un satélite de comunicaciones distribuye (entre otras cosas) las noticias de varias agencias de
noticias (p.ej Reuters, EFE, etc...). La agencia la constituyen una serie de reporteros distribuidos en
diferentes lugares, y envían sus noticias a la agencia cada vez que acontece una noticia.
Por otro lado los usuarios de la televisión por satélite, a través de su decodificador pueden enviar al
satélite una solicitud de suscripción a alguna de las agencias de noticias que distribuye. Esto
conlleva que cada vez que llega una nueva noticia a alguna agencia de noticias, se reenvía dicha
noticia a todos los clientes abonados a dicho canal.
Se pide:
1. Realiza un modelo de clases que recoja los requisitos descritos anteriormente, indicando
claramente si has utilizado algún patrón de diseño.
2. Implementa los métodos que estimes oportunos para llevar a cabo las funcionales descritas en los
requisitos.
SOLUCIÓN:
Obervable
*
1
Noticia
*
1
Agencia
1
*
Reportero
*
1
Satelite
«uses»
«interfaz»
Observer
+update()
Decodificador
Implementacion
public class Satelite {
Hashtable<String, Agencia> agencias=new Hashtable<String, Agencia>();
public Satelite() {
}
public void subscribe(String agencia,Decodificador dec) {
Agencia ag=agencias.get(agencia);
ag.addObserver(dec);
}
public void añadirAgencia(Agencia a){
agencias.put(a.nombreAgencia,a);
}
}
public class Agencia extends Observable{
Noticia ultimaNoticia;
String nombreAgencia;
Vector<Noticia> noticias=new Vector<Noticia>();
public Agencia(String agencia) {
nombreAgencia=agencia;
}
public void nuevaNoticia(String n){
ultimaNoticia=new Noticia(n);
noticias.add(ultimaNoticia);
this.setChanged();
this.notifyObservers(this);
}
}
public class Decodificador implements Observer {
String nombreDeco;
public Decodificador(String s) {
nombreDeco=s;
}
public void update(Observable t, Object o){
Agencia ag=(Agencia)t;
System.out.println("");
System.out.println("Decodificador: "+nombreDeco);
System.out.println("Agencia:"+ag.nombreAgencia);
System.out.println("Noticia:"+ag.ultimaNoticia.getNoticia());
}
}
public class Principal {
public Principal() {
}
public static void main(String args[]){
Satelite s=new Satelite();
Agencia ag1=new Agencia("EFE");
Agencia ag2=new Agencia("Reuters");
s.añadirAgencia(ag1);
s.añadirAgencia(ag2);
Decodificador d1=new Decodificador("deco 1");
Decodificador d2=new Decodificador("deco 2");
s.subscribe("EFE",d1);
s.subscribe("EFE",d2);
s.subscribe("Reuters",d2);
ag1.nuevaNoticia("La real ganó por fin");
ag2.nuevaNoticia("3-1 para la real");
}
}
Resultado
Decodificador: deco 2
Agencia:EFE
Noticia:La real ganó por fin
Decodificador: deco 1
Agencia:EFE
Noticia:La real ganó por fin
Decodificador: deco 2
Agencia:Reuters
Noticia:3-1 para la real
5ª PREGUNTA: EJB (2 ptos.) (Tiempo estimado: 45 minutos) Una empresa quiere desarrollar una
aplicación para jugar al ajedrez entre un usuario y el computador, donde las jugadas que se vayan
realizando se vayan plasmando en un tablero real donde las piezas son movidas por un brazo de un
robot. Para realizar esta aplicación nos proporcionan lo siguiente:
Un componente EJB TebleroEJB. Este componente gestiona un tablero(en memoria) y dispone de
los siguientes métodos:
void inicializarTablero()
boolean esPosibleJugada(Jugada j);
void mover(Jugada j);
boolean fin();
int quienHaGanado(); //1:User 2: Computador
Jugada mejorJugada(); //Cual es la mejor jugada por parte de la maquina
Un componente EJB RobotEJB que controla el brazo del robot y tiene los siguientes métodos:
void inicializarPartida() // Coloca las piezas en la posición inicial
void mover(Jugada j) // El brazo del robot aplica la jugada j en el tablero.
RobotEJB
PartidaEJB
TableroEJB
Con estos componentes implementados, nos piden:
1. Desarrollar un componente PartidaEJB, que utilizando los componentes anteriores implemente
los siguientes métodos:
//inicializa ambos componentes
void inicializar();
//Aplica la jugada j del usuario y a continuación aplica la jugada del computador si
no ha terminado la partida.
int jugadaUsuario(Jugada j);
boolean esFin(); //true si ha terminado la partida, y falso en caso contrario
String ganador(); //devuelve "Enhorabuena, has ganado" si ha ganado el usuario o
"Lo siento, inténtalo de nuevo", si ha ganado la computadora.
2. Realiza un programa principal, que inicialice una partida, y realice la ejecución de una partida.
(Tenemos un método Jugada leerJugada(); que lee de la entrada estándar una jugada por parte del
usuario).
SOLUCIÓN:
public interface PartidaEJBHome extends EJBHome {
PartidaEJB create() throws RemoteException, CreateException;
}
public interface PartidaEJB extends EJBObject {
void inicializarTablero() throws RemoteException;
boolean esPosibleJugada(Jugada j) throws RemoteException;
void mover(Jugada j) throws RemoteException;
boolean fin() throws RemoteException;
int quienHaGanado() throws RemoteException;
Jugada mejorJugada() throws RemoteException;
}
public class PartidaEJBBean implements SessionBean {
private SessionContext _context;
RobotEJB robotEJB;
TableroEJB tableroEJB;
public void ejbCreate() {
try {
Context context = getInitialContext();
PartidaEJBHome robotEJBHome = (RobotEJBHome)
PortableRemoteObject.narrow( context.lookup( "RobotEJB" ),
RobotEJBHome.class );
robotEJB = robotEJBHome.create( );
TableroEJBHome tableroEJBHome = (TableroEJBHome)
PortableRemoteObject.narrow( context.lookup( "TableroEJB" ),
TableroEJBHome.class );
tableroEJB = tableroEJBHome.create( );
} catch (Exception ex) {ex.printStackTrace(); }
}
Jugada jj=tableroEJB.mejorJugada();
tableroEJB.mover(j);
robotEJB.mover(j);
public void inicializar() {
robotEJB.inicializarPartida();
tableroEJB.inicializarTablero;
}
}
}
public void jugadaUsuario(Jugada j) {
if(tableroEJB.esPosibleJugada(j)) {
tableroEJB.mover(j);
robotEJB.mover(j);
if (!tableroEJB.fin)) {
}
public boolean esFin() {
return tableroEJB.fin();
}
public String ganador() {
if (tableroEJB.quineHaGanado()==1)
return "Enhorabuena, has ganado";
else return "Lo siento, intentalo de nuevo";
Programa Principal
public class PartidaEJBClient1 {
public static void main(String [] args) {
try {
Context context = getInitialContext();
PartidaEJBHome partidaEJBHome =
(PartidaEJBHome) PortableRemoteObject.narrow
( context.lookup( "PartidaEJB" ), PartidaEJBHome.class );
PartidaEJB partidaEJB;
partidaEJB = partidaEJBHome.create( );
Jugada j;
while (!partidaEJB.esFin()){
j=leerJugada();
PartidaEJB.mover(j);
}
System.out.println(partidaEJB.ganador());
} catch (Exception ex) {
ex.printStackTrace();
}
}