Download Enunciados de problemas

Document related concepts
no text concepts found
Transcript
EJERCICIOS SOBRE ARQUITECTURAS SOFTWARE DE VARIOS NIVELES
1.- La interfaz de usuario asociada a un caso de uso llamado CONSULTAR PRECIO
aparece a continuación, junto con la clase Java correspondiente:
import java.awt.*;
import java.awt.event.*;
public class ConsPrecioIU extends Frame {
Label label1 = new Label();
Panel panel1 = new Panel();
Button button1 = new Button();
Button button2 = new Button();
Panel panel2 = new Panel();
GridLayout gridLayout1 = new GridLayout(3,2);
Label label2 = new Label();
TextField textField1 = new TextField();
Label label3 = new Label();
TextField textField2 = new TextField();
Label label4 = new Label();
TextField textField3 = new TextField();
public ConsPrecioIU() {
super();
try {
jbInit();
}
catch (Exception e) {
e.printStackTrace();
}
}
private void jbInit() throws Exception {
this.setTitle("Frame Title");
label1.setText("CONSULTAR PRECIO");
label1.setAlignment(Label.CENTER);
button1.setLabel("Consultar Precio");
button1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
button1_actionPerformed(e); } });
button2.setLabel("Cancelar");
button2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
button2_actionPerformed(e); } });
label2.setText("MANZANAS (Kg.)");
label3.setText("PERAS (Kg.)");
label4.setText("NARANJAS (Kg.)");
panel2.setLayout(gridLayout1);
this.add(label1, BorderLayout.NORTH);
this.add(panel1, BorderLayout.SOUTH);
panel1.add(button1, null);
panel1.add(button2, null);
this.add(panel2, BorderLayout.CENTER);
panel2.add(label2, null);
panel2.add(textField1, null);
panel2.add(label3, null);
panel2.add(textField2, null);
panel2.add(label4, null);
panel2.add(textField3, null);
this.pack();
this.setVisible(true);}
void button1_actionPerformed(ActionEvent e) {...}
void button2_actionPerformed(ActionEvent e) {...}
}
Se dispone también de una clase llamada Aviso que sirve para crear Dialog modales
asociados al objeto Frame actual. La llamada new Aviso(this,"Pulsa Aceptar y
me voy"); crearía lo siguiente:
Además, nos han proporcionado los siguientes métodos, los cuales no sabemos ni a qué
clase pertenecen ni qué es lo que hacen exactamente, pero nos han dicho que son útiles
para acceder a los datos almacenados en la siguiente tabla de una BD Access. Además nos
dicen que dicha BD es accesible por medio de una fuente de datos ODBC llamada PRODS
public void inicializarBD () {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:PRODS");
sentencia=conexion.createStatement(); }
catch(Exception e){System.out.println("Error"+e.toString());} }
public float getPrecio(String nombre) {
try{ rs=sentencia.executeQuery("SELECT PRECIO FROM PRODUCTOS "+
"WHERE NOMBRE='"+nombre+"'");
if (rs.next()) return rs.getFloat("PRECIO");
} catch (Exception e) {System.out.println("Error: "+e.toString());}
return 0; }
Se pide: Rellenar la clase ConsPrecioIU con el código necesario para que al pulsar el
botón CONSULTAR PRECIO aparezca como resultado el precio de los productos
escogidos. Por ejemplo, el resultado sería el siguiente:
si los precios actuales fueran los que aparecen en la tabla ACCESS anterior y se hubiera
pulsado el botón CONSULTAR PRECIO con los siguientes datos de entrada:
La solución debe basarse en una arquitectura lógica en 3 niveles y ser extensible ante un
futuro cambio en la lógica del negocio, ya que se está pensando en “aplicar porcentajes de
descuento a cada producto dependiendo de la cantidad de Kg. que se compre”.
2.La interfaz de usuario asociada a un caso de uso llamado RESERVAR
LABORATORIO aparece a continuación, junto con las clases Java correspondientes:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ReservarLab extends JFrame {
JPanel jPanel1 = new JPanel();
JLabel jLabel1 = new JLabel();
BorderLayout borderLayout1 = new BorderLayout();
JPanel jPanel2 = new JPanel();
JComboBox jComboBox1 = new JComboBox();
JComboBox jComboBox2 = new JComboBox();
JButton jButton1 = new JButton();
JPanel jPanel3 = new JPanel();
GridLayout gridLayout1 = new GridLayout(6,6);
JTextField jTextField1 = new JTextField();
JTextField cajasTexto[][] = new JTextField[5][5];
GestorLabs gestor = new GestorLabs();
public ReservarLab() {
super();
try { jbInit(); }
catch (Exception e) { e.printStackTrace(); } }
private void jbInit() throws Exception {
this.setSize(new Dimension(400, 300));
jLabel1.setText("NOMBRE USUARIO:");
jPanel2.setLayout(gridLayout1);
jButton1.setText("Reservar");
this.getContentPane().setLayout(borderLayout1);
this.setTitle("Reservar Laboratorio");
jTextField1.setColumns(20);
this.getContentPane().add(jPanel1, BorderLayout.NORTH);
jPanel1.add(jLabel1, null);
jPanel1.add(jTextField1, null);
this.getContentPane().add(jPanel2, BorderLayout.CENTER);
jPanel2.add(new JLabel());
String etiqsDias[] = new String[5];
etiqsDias[0]="L"; etiqsDias[1]="M"; etiqsDias[2]="X";
etiqsDias[3]="J"; etiqsDias[4]="V";
for (int i=0;i<5;i++)
{ jPanel2.add(new JLabel(etiqsDias[i]));
jComboBox1.addItem(etiqsDias[i]); }
String etiqsHor[] = new String[5];
etiqsHor[0]="9-10"; etiqsHor[1]="10-11"; etiqsHor[2]="11-12";
etiqsHor[3]="12-13"; etiqsHor[4]="13-14";
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e); } }) ;
for (int i=0;i<5;i++) {
jPanel2.add(new JLabel(etiqsHor[i]));
jComboBox2.addItem(etiqsHor[i]);
for (int j=0;j<5;j++) {
cajasTexto[i][j] = new JTextField();
jPanel2.add(cajasTexto[i][j],numComp++); } }
dibujarReservas();
this.getContentPane().add(jPanel3, BorderLayout.SOUTH);
jPanel3.add(jButton1, null);
jPanel3.add(jComboBox1, null);
jPanel3.add(jComboBox2, null); }
public void dibujarReservas() {
for (int i=0;i<5;i++)
for (int j=0; j<5; j++) {
cajasTexto[i][j].setText(gestor.getReserva(j,i)); } }
void jButton1_actionPerformed(ActionEvent e) {
gestor.setReserva(jComboBox1.getSelectedIndex(),
jComboBox2.getSelectedIndex(),jTextField1.getText());
dibujarReservas(); } }
import java.sql.*;
public class GestorLabs extends Object {
Connection conexion; Statement sent; ResultSet rs;
public GestorLabs() {
try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Labs");
sent=conexion.createStatement();}
catch(Exception e) {System.out.println("Err:"+e.toString());} }
public String getReserva(int dia, int hora) {
try{ rs=sent.executeQuery("SELECT NOMBRE FROM RESERVAS "+
"WHERE DIA="+dia+" AND HORA="+hora);
if (rs.next()) return rs.getString("NOMBRE"); }
catch (Exception e) {System.out.println("Error: "+e.toString());}
return null; }
public void setReserva(int dia, int hora, String us) {
try{ sent.executeUpdate("UPDATE RESERVAS SET NOMBRE='"+us+"' "+
"WHERE DIA="+dia+" AND HORA="+hora+" AND NOMBRE='LIBRE'");
} catch (Exception e) {System.out.println("Error: "+e.toString());}
} }
Decir si la solución propuesta sigue una arquitectura lógica en 3 niveles. Si es así, indicar
qué partes del código corresponden a cada nivel. Si no es así, indicar qué habría que hacer
para conseguir que el software siguiera una arquitectura lógica en 3 niveles y qué partes
del código corresponderían a cada nivel.
3.- Una vez definido el software siguiendo una arquitectura lógica en 3 niveles (en el
ejercicio 2), definir cómo se puede conseguir una arquitectura física en 3 niveles.
4.- El diagrama de secuencia con el diseño del caso de uso “Buscar Personas Por Nombre”
Buscar Personas
Por Nombre
Usuario
es el siguiente:
: IU_VP
GBD: Statement
: GestorPersonas
usuario
escribir Nombre()
buscarPorNombre(nombre:String)
executeQuery("select * from persona where nombre= %nombre")
next()
new()
r: ResultSet
getString("nombre"),...,: getString("telefono")
new Persona(nombre:String, direccion:String, telefono:String)
Pi: Persona
P1, P2, ... Pn()
getNombre()
getDireccion()
getTelefono()
Esta es la interfaz gráfica de usuario correspondiente al caso de uso:
A continuación presentamos una implementación INCOMPLETA en Java de dicho caso
de uso utilizando una arquitectura física en tres niveles.
package jun02;
import
import
import
import
import
javax.swing.*;
java.awt.*;
java.awt.event.*;
java.util.*;
java.rmi.*;
public class IU_VP extends JFrame
{
JLabel jLabel1 = new JLabel();
JTextField jTextField1 = new JTextField();
JTextArea jTextArea1 = new JTextArea();
GestorPersonas g;
public IU_VP()
{
try
{
jbInit();
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void jbInit() throws Exception
{
jLabel1.setBounds(new Rectangle(17, 41, 130, 30));
this.getContentPane().setLayout(null);
this.setSize(new Dimension(400, 300));
this.setTitle("Pertsonen bilakatzaile / Buscador de Personas");
jLabel1.setRequestFocusEnabled(false);
jLabel1.setText("Izena / Nombre");
jTextField1.setBounds(new Rectangle(122, 40, 197, 33));
jTextField1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jTextField1_actionPerformed(e);
}
});
jTextArea1.setBounds(new Rectangle(45, 97, 261, 145));
this.getContentPane().add(jTextArea1, null);
this.getContentPane().add(jTextField1, null);
this.getContentPane().add(jLabel1, null);
}
public void setLogicaNegocio(GestorPersonas gp) {g=gp;}
void jTextField1_actionPerformed(ActionEvent e)
{
}
public static void main(String[] argc) {
IU_VP i = new IU_VP();
i.setVisible(true);
try{
System.setSecurityManager(new RMISecurityManager());
String url =
i.setLogicaNegocio((GestorPersonas)Naming.lookup(url));
}
catch (Exception ex) { }
}
}
package jun02;
import com.objectspace.jgl.Container;
public interface GestorPersonas
{
/** Método que busca personas con un determinado nombre
* @param n Nombre de la persona a buscar
* @return Container con los objetos de Persona que tienen dicho
nombre
*/
Container buscarPorNombre(String n)
}
package jun02;
public class Persona
{
private String nombre;
private String direccion;
private String telefono;
public Persona(String n, String dir, String tel)
{ nombre=n; direccion=dir; telefono=tel; }
public String getNombre(){return nombre;}
public String getDireccion() {return direccion;}
public String getTelefono() {return telefono;}
}
package jun02;
import java.rmi.server.*;
import java.rmi.*;
import
import
import
import
java.sql.*;
java.util.*;
com.objectspace.jgl.Container;
com.objectspace.jgl.Array;
public class ImplGestorPersonas
{ PreparedStatement s;
Connection o;
public ImplGestorPersonas() throws RemoteException {
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
o=DriverManager.getConnection("jdbc:odbc:BDPers");
s=o.prepareStatement("select nombre, direccion, telefono"+
" from persona where nombre like ?"); }
catch (Exception ex){System.out.println("Error: "+ex.toString());}
}
public Container buscarPorNombre(String n) throws RemoteException
{
Array v=new Array();
}
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try { ImplGestorPersonas objetoServidor = new ImplGestorPersonas();
try { java.rmi.registry.LocateRegistry.createRegistry(1200); }
catch (Exception e) {System.out.println("Rmiregistry ya
lanzado");}
Naming.rebind("//localhost:1200/gestorPersonas",
);
System.out.println("Lanzado el objeto servidor");
} catch (Exception e)
{System.out.println("Error al lanzar el
servidor"+e.toString());}
}}
Se pide implementar el código correspondiente a la respuesta al evento “escribir un
nombre en la caja de texto de la interfaz gráfica de usuario”, la implementación del
método buscarPor Nombre y las llamadas a los métodos lookup y rebind de RMI.
Además existen algunos errores claros que hay que corregir.
5.- El diagrama de secuencia con el diseño del caso de uso “Buscar Personas Por Teléfono”
Buscar Personas
Por Telefono
Usuario
es el siguiente:
: IU_VP
GBD: Statement
: GestorPersonas
usuario
escribir Telefono()
buscarPorTelefono(telefono:String)
buscarPorTelefonoEnTablaHash(telefono:String)
[están en tabla Hash]: P1, ... Pn()
[no están en tabla Hash]: executeQuery("select * from persona where telefono= %telefono")
new()
r: ResultSet
next()
getString("nombre"),...,: getString("telefono")
new Persona(nombre:String, direccion:String, telefono:String)
Pi: Persona
aniadirATablaHash(Pi)
P1, P2, ... Pn()
getNombre()
getDireccion()
Esta es la interfaz gráfica de usuario correspondiente al caso de uso:
A continuación presentamos una implementación INCOMPLETA en Java de dicho caso
de uso utilizando una arquitectura física en tres niveles.
package jun02;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.rmi.*;
public class IU_VPT extends JFrame
{
JLabel jLabel1 = new JLabel();
JTextField jTextField1 = new JTextField();
JTextArea jTextArea1 = new JTextArea();
GestorPersonas g;
public IU_VPT()
{ try
{ jbInit(); }
catch(Exception e)
{ e.printStackTrace();
}
}
private void jbInit() throws Exception
{ jLabel1.setBounds(new Rectangle(17, 41, 131, 30));
this.getContentPane().setLayout(null);
this.setSize(new Dimension(400, 300));
this.setTitle("Pertsonen bilatzaile / Buscador de Personas");
jLabel1.setRequestFocusEnabled(false);
jLabel1.setText("Telefonoa / Teléfono");
jTextField1.setBounds(new Rectangle(149, 40, 170, 33));
jTextField1.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e)
{
jTextField1_actionPerformed(e);
}
});
jTextArea1.setBounds(new Rectangle(45, 97, 261, 145));
this.getContentPane().add(jTextArea1, null);
this.getContentPane().add(jTextField1, null);
this.getContentPane().add(jLabel1, null);
}
public void setLogicaNegocio(GestorPersonas gp) {g=gp;}
void jTextField1_actionPerformed(ActionEvent e)
{
}
public static void main(String[] argc) {
IU_VPT i = new IU_VPT();
i.setVisible(true);
try{
System.setSecurityManager(new RMISecurityManager());
String url = "rmi://
:1210/
";
i.setLogicaNegocio((GestorPersonas)Naming.lookup(url));
}
catch (Exception ex)
{i.jTextArea1.setText("Error al asignar la lógica del negocio\n");
i.jTextArea1.append(ex.toString());}
}
}
package jun02;
import com.objectspace.jgl.Container;
public interface GestorPersonas extends java.rmi.Remote
{
/** Método que busca personas con un determinado teléfono
* @param t Teléfono de la persona a buscar
* @return Container con los objetos de Persona que tienen dicho nombre
*/
Container buscarPorTelefono(String t)
}
package jun02;
public class Persona implements Cloneable
{
private String nombre;
private String direccion;
private String telefono;
public Persona(String n, String dir, String tel)
{ nombre=n; direccion=dir; telefono=tel; }
public String getNombre(){return nombre;}
public String getDireccion() {return direccion;}
public String getTelefono() {return telefono;}
}
package jun02;
// Esta es la clase servidora RMI
import java.rmi.server.*;
// Se ejecuta en la máquina servRmi.si.ehu.es
import java.rmi.*;
import java.sql.*;
import java.util.*;
import com.objectspace.jgl.*;
public class ImplGestorPersonas extends UnicastRemoteObject
{ Statement t;
Connection o;
HashMap personas;
public ImplGestorPersonas() throws RemoteException
{
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
o=DriverManager.getConnection("jdbc:odbc:BDPers");
// En la BD existe la tabla persona(nombre,direccion,telefono)
personas = new HashMap();
}
catch (Exception ex){System.out.println("Error: "+ex.toString());}
}
public Container buscarPorTelefono(String tfno) throws
java.rmi.RemoteException
{
}
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try {
ImplGestorPersonas objetoServidor = new ImplGestorPersonas();
try { java.rmi.registry.LocateRegistry.createRegistry(1099);
// Equivalente a lanzar RMIREGISTRY
} catch (Exception e) {System.out.println("Rmiregistry ya lanzado");}
Naming.rebind("//localhost:
/gestorPersonas",
);
System.out.println("Lanzado el objeto servidor");
} catch (Exception e)
{System.out.println("Error al lanzar el servidor"+e.toString());} } }
Se pide implementar el código correspondiente a la respuesta al evento “escribir un
nombre en la caja de texto de la interfaz gráfica de usuario”, la implementación del
método buscarPorTelefono, las llamadas a los métodos lookup y rebind de RMI, y
añadir el código que se considere necesario. Además existen algunos errores claros que
hay que corregir.
NOTA: la clase servidora RMI se ejecutará en el ordenador con el nombre IP:
servRmi.si.ehu.es, y NO SE PUEDE SUPONER que sea el mismo ordenador en el que se
ejecuten los clientes RMI.
6.- La siguiente clase (Presentacion.java) implementa el caso de uso SOLICITAR
COMIDA, que muestra una lista de primeros platos, otra de segundos platos y permite
solicitar una comida compuesta por un primer y un segundo plato.
Los nombres de los platos se obtienen de la siguiente tabla PLATO y las solicitudes de
comidas se almacenan en la tabla PEDIDO.
Se pide: Proponer una solución que utilice una arquitectura física en 3 niveles y que
además fuera extensible ante el siguiente “posible” nuevo requisito: los menús podrán
estar formados por otros tipos de platos (como postres, entrantes, etc.) como aparece en la
siguiente interfaz de usuario. Con que la solución sea extensible nos referimos en concreto
a que no debería cambiar ni el nivel de presentación ni el de la lógica del negocio una vez
que ese nuevo requisito fuera incorporado a la aplicación. Tan sólo el nivel de datos podría
cambiar. Indicar cuáles serían esos cambios.
En la solución propuesta deben mostrarse las clases necesarias en notación UML, junto
con la signatura de los métodos de las mismas. No hay que implementar la solución, pero
sí se debe mostrar el uso de Java RMI, Java JDBC e interfaces Java. Esto se puede
representar por medio de dependencias “usa”, generalizaciones e implementación de
interfaces en UML.
El código es el siguiente:
package menuDia;
import javax.swing.*;
import java.awt.*;
import java.sql.*;
import java.awt.event.*;
public class Presentacion extends JFrame
{
JPanel jPanel1 = new JPanel();
JLabel jLabel1 = new JLabel();
DefaultComboBoxModel l1 = new DefaultComboBoxModel();
JComboBox jComboBox1 = new JComboBox(l1);
JLabel jLabel2 = new JLabel();
DefaultComboBoxModel l2 = new DefaultComboBoxModel();
JComboBox jComboBox2 = new JComboBox(l2);
JButton jButton1 = new JButton();
Statement st;
Connection o;
ResultSet rs;
public Presentacion()
{
try{ jbInit(); } catch(Exception e) { e.printStackTrace();}
}
private void jbInit() throws Exception
{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
o=DriverManager.getConnection("jdbc:odbc:menus");
st= o.createStatement();
this.setTitle("Solicitar Menu");
jPanel1.setLayout(new GridLayout(2,2));
jLabel1.setText("Primeros");
jLabel2.setText("Segundos");
jButton1.setText("Solicitar Comida");
jPanel1.add(jLabel1);
jPanel1.add(jComboBox1);
rs =st.executeQuery("select nombre from plato where tipo = 'Primeros'");
while (rs.next())
l1.addElement(rs.getString("nombre"));}
jPanel1.add(jLabel2);
jPanel1.add(jComboBox2);
rs =st.executeQuery("select nombre from plato where tipo = 'Segundos'");
jButton1.addActionListener(new ActionListener()
{public void actionPerformed(ActionEvent e)
{ jButton1_actionPerformed(e); } });
while (rs.next())
{l2.addElement(rs.getString("nombre"));}
this.getContentPane().setLayout(new GridLayout(2,1));
this.getContentPane().add(jPanel1);
this.getContentPane().add(jButton1);
pack(); }
void jButton1_actionPerformed(ActionEvent e)
{ try {st.executeUpdate("insert into pedido (primPlato,segPlato) values ('"+
jComboBox1.getSelectedItem()+"','"+jComboBox2.getSelectedItem()+"')");
} catch(Exception ex) {ex.printStackTrace();} } }
public static void main(String[] args) {
Presentacion p = new Presentacion();
p.setVisible(true); }
7.- Como continuación al ejercicio anterior se pide dar una solución extensible en la que ni
siquiera tuviéramos que cambiar el nivel de datos.
8.- A continuación se muestra la solución del ejercicio 6, que supondremos está ya
implementada, y se presentan unos cambios en los requisitos que se deben realizar.
SOLUCIÓN:
«interface»
java.rmi.Remote
Presentacion
«uses»
-logNeg : Menus
«interface»
Menus
+getTiposPlatos() : Enumeration
+getPlatos(in tipoPlato : string) : Enumeration
+solicitarMenu(in platos : Enumeration)
«uses»
java.sql
«datatype»
java.rmi.UnicastRemoteObject
ServidorMenus
NOTA referente a ServidorMenus:
===========================
Hace rebind("rmi://localhost:"+puerto+"/menus", objetoServidor)
Se supone que se ejecuta en la máquina "serv"
NOTA referente a Presentacion:
==========================
Abre una conexión con una BD con estas tablas
Hace lookup("rmi://serv:"+puerto+"/menus")
y dejar en logNeg
PLATO(nombre,tipo)
PEDIDO(num,primeros,segundos,...)
Crea tantos JLabel y JComboBox como elementos
haya en logNeg.getTiposPlatos()
En el JLabel i-ésimo pondremos el tipo de plato i-ésimo
En el JComboBox i-ésimo se pondrán los platos
devueltos por logNeg.getPlatos("tipo de plato i-ésimo")
getTipoPlatos() preguntaría "select tipo from PLATO"
getPlatos(t) preguntaría "select nombre from PLATO where tipo= %t"
solicitarMenu(platos) realizaría el insert:
insert into PEDIDO (num,%tipoPlato[1],%tipoPlato[2],...)
values (NUMNUEVO,%platos[1],%platos[2],...)
con platos[i] el nombre del plato pasado en el parámetro "platos"
y tipoPlato[i] es el tipo correspondiente a dicho plato
NOTA: el nombre del tipo de plato en la tabla PLATO
coincide con el nombre del atributo en la tabla PEDIDO
Si se añadiera un nuevo tipo de plato (pongamos “Entremeses”), sólo habría que cambiar
la BD:
- En la tabla PLATO añadiríamos las tuplas: <”fritos”,”Entremeses”>, <”pimientos
rellenos”,”Entremeses”>,...
- En la tabla PEDIDO añadiríamos una columna llamada “Entremeses”
Cambios en los requisitos. A partir de este momento nos indican que “existen platos
incompatibles con otros, esto es, que no pueden ser solicitados en un mismo menú”. Por
ejemplo: si se pide macarrones no se puede pedir filete. Cada incompatibilidad está
formada por un plato de un grupo y otro plato de otro grupo distinto. Además se desea
que cuando el usuario seleccio ne uno de los platos en la interfaz gráfica (en la lista
desplegable correspondiente), automáticamente se eliminen sus platos incompatibles en las
listas desplegables correspondientes a los demás tipos de platos.
Se pide:
A) Indicar si dichos cambios deben afectar al nivel de presentación, al nivel de lógica
del negocio o al nivel de datos, razonando la respuesta.
¿Afectan al nivel de presentación? Sí / No
¿Por qué?
¿Afectan al nivel de lógica del negocio? Sí / No ¿Por qué?
¿Afectan al nivel de datos? Sí / No ¿Por qué?
B) Realizar los cambios que se consideren necesarios (en el diagrama de clases UML,
en la base de datos, etc.) para adaptar el caso de uso “Solicitar Menu” a los nuevos
requisitos. Indicar además cómo sería la implementación (sólo en qué cambiaría la
implementación actual que se supone ya tenemos)
NOTA: no se pide realizar los cambios para añadir platos incompatibles en el sistema.
Sólo los necesarios para que el CU “Solicitar Menu” funcione.
9.- Una vez que el caso de uso “ENTRAR EN EL SISTEMA” (realizado en los
laboratorios de la asignatura) se ha construido y desplegado utilizando una arquitectura
física en 3 niveles podríamos preguntarnos si la aplicación ES EXTENSIBLE. En general,
no se puede afirmar si es extensible o no, sino más bien, si es extensible ante un cambio en
concreto.
A continuación se van a plantear una serie de cambios en los requisitos de la aplicación y
habrá que comprobar si la aplicación es extensible en ese caso.
POSIBLES CAMBIOS EN LOS REQUISITOS:
-
Se desea cambiar la base de datos de MS Access a MySQL
Se desea que el número de intentos para hacer login con una cuenta se reduzca de
3 a 2.
Se desea cambiar el nombre del atributo “password” de la tabla “cuenta” por
“clave”
Se desea que, en la ventana gráfica, el campo de texto en el que se introduce el
nombre de usuario también muestre asteriscos en vez de dicho nombre.
Se desea que en la ventana de presentación, una vez que haya hecho login diga
cuándo fue la última vez que hizo login
Se desea que cuando e l nombre de cuenta sea “administrador” (y sólo para esa
cuenta) sólo permita un único intento para entrar en el sistema
Se desea que las cuentas incluyan por lo menos un carácter numérico o especial (; $ :)
En concreto hay que plantearse las siguientes preguntas :
1.- ¿Hay que reinstalar los drivers de la BD? Si es así, ¿en qué nodos? (nodos con la
presentación, en los servidores de aplicaciones (los que contienen la lógica de aplicaciones),
en el servidor de base de datos? ¿Cuál sería el cambio exacto en el código fuente, si es
necesario?
2.- ¿Hay que reconfigurar la BD? Si es así, ¿en qué nodos? ¿Cuál sería el cambio exacto en
el código fuente, si es necesario?
3.- ¿Hay que recompilar el nivel de presentación? Si es así, ¿en qué nodos? ¿Cuál sería el
cambio exacto en el código fuente, si es necesario?
4.- Si no hubiera que recompilar el nivel de presentación, ¿habría que volver a ejecutar la
aplicación?
5.- ¿Hay que recompilar la lógica del negocio? Si es así, ¿en qué nodos? ¿Cuál sería el
cambio exacto en el código fuente, si es necesario?
6.- ¿Hay que cambiar la BD? Si es así, ¿en qué nodos? ¿Cuál sería el cambio exacto en el
código fuente, si es necesario?
En el supuesto en que alguna de las respuestas nos confirme que la solución NO ES
EXTENSIBLE, indicar cómo tendría que haber sido para que hubiera sido extensible.
10.- 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.
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" />
<jsp:setProperty name="logNegocio" property="dni" param="dni" />
<%-- Equivalente a: <% logNegocio.setDni(request.getParameter("dni")); --%>
<% String fecha =
request.getParameter("dia")+"/"+request.getParameter("mes")+"/04";%>
<jsp:setProperty name="logNegocio" property="fecha" value="<%= fecha %>"/>
<jsp:setProperty name="logNegocio" property="numMins" param="minutos"/><p>
RESULTADO: <jsp:getProperty name="logNegocio" property="resultado" />
</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 Ge storRegistrarHoras.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());}}}
11.- 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.
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.getParameter("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());}}}
12.- A continuación se presenta una IMPLEMENTACIÓN COMPLETA en 3 NIVELES
FÍSICOS DEL CASO DE USO PEDIR BILLETE
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());}}}
Indicar si la aplicación es extensible ante los siguientes cambios en los requisitos:
•
•
•
•
Se desea cambiar el SGBD de Access a MySQ L
Se desea cambiar la BD; cambiar de nombre a la tabla BILLETES por el nombre
ENTRADAS
Se desea añadir una nueva regla del negocio: no permitir comprar más de 6
entradas a la misma persona
Se desea que la respuesta a “Pedir Billete” salga en otra ventana
En concreto hay que plantearse las siguientes preguntas :
1.- ¿Hay que reinstalar los drivers de la BD? Si es así, ¿en qué nodos? (nodos con la
presentación, en los servidores de aplicaciones (los que contienen la lógica de aplicaciones),
en el servidor de base de datos? ¿Cuál sería el cambio exacto en el código fuente, si es
necesario?
2.- ¿Hay que reconfigurar la BD? Si es así, ¿en qué nodos? ¿Cuál sería el cambio exacto en
el código fuente, si es necesario?
3.- ¿Hay que recompilar el nivel de presentació n? Si es así, ¿en qué nodos? ¿Cuál sería el
cambio exacto en el código fuente, si es necesario?
4.- Si no hubiera que recompilar el nivel de presentación, ¿habría que volver a ejecutar la
aplicación?
5.- ¿Hay que recompilar la lógica del negocio? Si es as í, ¿en qué nodos? ¿Cuál sería el
cambio exacto en el código fuente, si es necesario?
6.- ¿Hay que cambiar la BD? Si es así, ¿en qué nodos? ¿Cuál sería el cambio exacto en el
código fuente, si es necesario?
En el supuesto en que alguna de las respuestas nos confirme que la solución NO ES
EXTENSIBLE, indicar cómo tendría que haber sido para que hubiera sido extensible.