Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ingeniería en Informática
Facultad de Informática
UPV/EHU
Departamento de Lenguajes
y Sistemas Informáticos
Tema 2:
Arquitecturas Software de varios
niveles en Java
Índice
• Arquitecturas Software de varios niveles
• Construcción de interfaces gráficas en Java: AWT y
Swing
• Conexión con BDs relacionales en Java: JDBC
• Persistencia de objetos en Java: mecanismos de
serialización
• Introducción a la computación distribuida en Java:
RMI
• Tecnología Java para la construcción de aplicaciones
web: Applets, JSPs
• Servicios Web
A. Goñi. Dpto. LSI, UPV/EHU
4
1. Arquitecturas Software de
varios niveles
Índice
• Introducción
• Arquitectura lógica del software en
niveles: presentación, lógica del
negocio y datos.
• Arquitectura física en 2 niveles: cliente
gordo/servidor flaco
• Arquitectura física en 2 niveles: cliente
flaco/servidor gordo
• Arquitectura física en 3 (o más) niveles
A. Goñi. Dpto. LSI, UPV/EHU
6
Introducción
BASE DE DATOS
Se puede implementar en una sola clase (véase
PedirBilleteNO3NIVELES) en nodos cliente, dejando la
base de datos en un nodo servidor
A. Goñi. Dpto. LSI, UPV/EHU
8
PRESENTACIÓN
public static void main (String []arg) {
PedirBilleteNO3NIVELES b = new PedirBilleteNO3NIVELES();
b.setVisible(true);}}
A. Goñi. Dpto. LSI, UPV/EHU
10
NIVEL DE NIVEL DE
PRESENTACIÓN DATOS
NIVEL DE LÓGICA
DEL NEGOCIO
representan
representan
NIVEL DE DATOS
• Clases ENTIDAD
representan
getBillete(nombre) Datos
executeQuery:=executeQuery( P1)
: ResultSet
new()
Presentación next()
next()
num
executeUpdate:=executeUpdate(P2)
b : Billete
new(num, nom)
CLIENTE SERVIDOR
Nivel de Datos
BASE DE
DATOS
SERVIDOR APLICACIONES
INSTALAR LA public class ServidorGestorBilletesBD
CLASE implements GestorBilletes Lógica del Negocio
sun.jdbc.odbc. { public ServidorGestorBilletesBD() {
JdbcOdbcDriver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
Y DEFINIR public Billete getBillete(String nom)
FUENTE {ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
DATOS ODBC int act = sent.executeUpdate("UPDATE BILLETES …“);
“Billetes” if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
A. Goñi. Dpto. LSI, UPV/EHU
27
BD
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
CLIENTE APLICACIONES
CLIENTE
CLIENTE sun.jdbc.odbc.JdbcOdbcDriver SERVIDOR
CLIENTE SERVIDOR
CLIENTE APLICACIONES DATOS
CLIENTE
CLIENTE
CLIENTE SERVIDOR
CLIENTE APLICACIONES
CLIENTE
CLIENTE sun.jdbc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE
CLIENTE ¡¡ SÓLO LOS SERVIDORES
CLIENTE DE APLICACIONES TIENEN
CLIENTE CONEXIONES ABIERTAS
CLIENTE
CON LA BD!!
A. Goñi. Dpto. LSI, UPV/EHU
28
Nivel de Datos
BASE DE
A. Goñi. Dpto. LSI, UPV/EHU DATOS
30
CLIENTE SERVIDOR
BD Datos
WEB
Navegador
HTML + JSP +
Web
Bean
Ejecutar Instalar
Presentación Presentación
SERVIDOR
DATOS
SERVIDOR APLICACIONES
INSTALAR LA public class ServidorGestorBilletesBD
CLASE implements GestorBilletes Lógica del Negocio
sun.jdbc.odbc. { public ServidorGestorBilletesBD() {
JdbcOdbcDriver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
Y DEFINIR public Billete getBillete(String nom)
FUENTE {ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
DATOS ODBC int act = sent.executeUpdate("UPDATE BILLETES …“);
“Billetes” if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
A. Goñi. Dpto. LSI, UPV/EHU
31
BD
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
APLICACIONES
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
APLICACIONES
2. Construcción de
interfaces gráficas en Java
AWT y Swing
Índice
• Introducción
– Objetivos
– La jerarquía de clases: patrón de diseño Composite
• Componentes principales
– Contenedores de AWT/Swing
– Componentes de AWT/Swing
– Administradores de diseño
• Gestión de Eventos
– Eventos de bajo y alto nivel
– Listeners
– Adapters
• Separación entre Nivel de Presentación y Lógica
del Negocio usando interfaces Java.
A. Goñi. Dpto. LSI, UPV/EHU
37
Introducción
• Es interesante disponer de herramientas
de ayuda para la construcción de
interfaces gráficas de usuario (GUI).
• Java proporciona clases para conseguir:
– Diseño y programación de interfaces fácil y
rápido.
– Diseño de Applets para la Web.
• En concreto, Java proporciona
– clases AWT (Abstract Windowing Toolkit)
– clases Swing
• Swing es posterior a AWT y tiene más componentes
A. Goñi. Dpto. LSI, UPV/EHU
38
Introducción
• Objetivos
– Entender la jerarquía de clases diseñada en
Java que permite construir interfaces de usuario
– Entender cómo se realiza la gestión de eventos
– NO es objetivo aprender los nombres de todas
las clases, listeners... Al fin y al cabo se pueden
construir interfaces de usuario usando
herramientas de desarrollo Java
(ej: JDeveloper)
COMPONENTE
Applet
CONTENEDOR
(todo contenedor es
un componente)
A. Goñi. Dpto. LSI, UPV/EHU
40
Componente
Applet
CONTENEDOR
(todo contenedor es
Las posibilidades son infinitas…
un componente)
- Una ventana formada por 2 cajas de texto, 2 campos de texto, 3 botones, 1
panel que contenga 5 casillas de validación y una lista desplegable.
-Una ventana formada por 2 etiquetas, 2 campos de texto y un botón
-…
Además, añadir nuevos tipos de contenedores y de componentes no sería muy
costoso (estaríamos ante una solución extensible)
A. Goñi. Dpto. LSI, UPV/EHU
42
* Frame
TextField
* …
- Se necesitarían métodos addButton, addCheckBox, addTextField,
addFrame en la clase Frame (y los correspondientes a todos los que faltan)
- Además el diagrama está muy incompleto, ya que un Button puede ser
componente de un Panel, Dialog, …
- Si se quisiera añadir un nuevo componente XXX, habría que cambiar la
clase Frame y añadir el método addXXX (nada extensible)
A. Goñi. Dpto. LSI, UPV/EHU
43
Applet
JComponent JMenuBar
JWindow
JFrame JTextField,
JDialog
JPanel JList JComboBox JTextArea,
JApplet JButton…
Contenedores
jPanel4 jComboBox1
jRadioButton1
jPanel3
jPanel2 jRadioButton2
jTextArea1
jButton1
jPanel1
JDeveloper genera el
código añadiendo el método
jbInit y capturando cualquier
posible excepción. No lo
pondremos así en los siguientes
ejemplos por ahorrar espacio.
A. Goñi. Dpto. LSI, UPV/EHU
49
Componentes principales
de AWT / Swing
JFrame
• Clases
Checkbox/JCheckBox/JRadioButton
– Las casillas de verificación permiten ofrecer al
usuario la posibilidad de activar/desactivar
opciones.
– Los JRadioButton pueden añadirse a
ButtonGroup si se debe ESCOGER SÓLO
UNA OPCIÓN
– En AWT puede conseguirse el mismo resultado
si los Checkbox se definen dentro de un mismo
Checkboxgroup
A. Goñi. Dpto. LSI, UPV/EHU
52
Se puede
redimensionar…
Modificar valores
en celdas…
Menús en Swing
JMenu
JMenu
JMenuBar
JMenuItem JMenuItem
Menús en AWT
Objeto de MenuBar
Objeto de MenuItem
Objeto de Menu
Objeto de MenuShort
Objeto de Menu
Objeto de CheckboxMenuItem
A. Goñi. Dpto. LSI, UPV/EHU
64
Label Panel
en BorderLayout.NORTH con BorderLayout
jPanel1
jPanel2
Sin administrador de
diseño. Se dan las
coordenadas de todos los
componentes (usando una
herramienta visual es fácil)
A. Goñi. Dpto. LSI, UPV/EHU
71
Como desventaja clara, es que
al redimensionar el Frame, los
componentes se quedan donde
estaban. Se podría programar
el evento asociado a
redimensionar la ventana y
recalcular las coordenadas…
Otros contenedores
• Clases Dialog/JDialog
– Ventana que permite leer datos del usuario
– Puede asignársele la característica de ser MODAL, para
no permitir cambiar a otra ventana mientras esté activa.
• Clase FileDialog (AWT) / JFileChooser (Swing)
– Ventana que permite abrir/guardar ficheros (modos
FileDialog.LOAD y FileDialog.SAVE)
– En AWT, se utiliza la misma ventana de diálogo del
Sistema Operativo en el que se está ejecutando la
máquina virtual Java
– Ofrece ya cierta funcionalidad. No hay que reprogramar el
caso en el que se intenta sobreescribir un fichero (muestra
ventana de alerta)
A. Goñi. Dpto. LSI, UPV/EHU
73
modal
a true
Gestión de eventos
Eventos
• Evento es un suceso
– generado por una acción del usuario
– que afecta a algún componente de la
interfaz
• Ejemplos de eventos:
– pulsar una tecla, mover el ratón, cambiar el
formato de una ventana, cerrar una venta,
minimizar una ventana, pulsar un botón, se
pierde (o gana) el foco en un componente,
se cambia el valor de un área de texto,
seleccionar un item en el menú, etc.
A. Goñi. Dpto. LSI, UPV/EHU
77
Tipos de eventos
• Eventos de bajo nivel
– Relacionados con aspectos físicos de la interfaz
de usuario. Ejemplos: pulsación de teclas,
movimientos de ratón, hacer click, ganar/perder el
foco en un componente, abrir/cerrar ventana..
• Eventos de alto nivel o semánticos
– Tienen que ver con la semántica de los
componentes. Ejemplos: pulsar un botón, cambiar
el texto de un campo, seleccionar un item en un
menú/lista/choice
– Generalmente son combinaciones de eventos de
bajo nivel.
A. Goñi. Dpto. LSI, UPV/EHU
78
Interfaces Listener
• Para gestionar eventos, Java proporciona
unas interfaces “oyentes” (Listeners),
donde cada una de ellas contiene métodos
que hay que implementar.
• La implementación proporcionada para
cada método es la respuesta apropiada a
cada evento.
• Si sobre un objeto gráfico queremos
controlar cierto tipo de eventos, le
asignaremos un “listener”
objGraf.addXXXListener(objListener)
A. Goñi. Dpto. LSI, UPV/EHU
81
obj1.addXXXListener(obj2);
Tras pulsar
el botón
2) Seleccionar el
Evento
(actionPerformed)
1) Hacer click en el componente y hacer click
3) Escribir el
código donde
indica JDeveloper
Clases Adapter
Tras pulsar
el botón
button1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
button1_actionPerformed(e);
ESTE CÓDIGO }
SE GENERA DE });
MANERA LA ACCIÓN HAY QUE
AUTOMÁTICA PROGRAMARLA, CLARO
CON JDeveloper
void button1_actionPerformed(ActionEvent e) {
textArea1.setText("Opción: "+checkboxGroup1.getCurrent().getLabel());
}
A. Goñi. Dpto. LSI, UPV/EHU
88
Punto donde se
encuentra el ratón
jTextField1
Interface LogicaNegocio
hacerX(… )
hacerY(… )
usa
Clase Presentacion
logNe: LogicaNegocio
En alguno de los métodos de la clase
Presentación (los que responden a eventos)
se usará:
setLogicaNegocio
logNe.hacerX(…)
(l: LogicaNegocio)
o bien
logNe.hacerY(…)
hacerX(… )
hacerY(… )
usa
Clase Presentacion
logNe: LogicaNegocio
clase LogicaNegocioConcreta
hacerX(… ) // Implementada
setLogicaNegocio hacerY(… ) // Implementada
(l: LogicaNegocio)
setLogicaNegocio
(l: LogicaNegocio) clase LogicaNegocionNueva
hacerX(… ) // Implementada
hacerY(… ) // Implementada
Si ahora se quisiera cambiar la lógica del negocio, bastaría con
hacer: p.setLogicaNegocio(new LogicaNegocioNueva());
NO HACE FALTA RECOMPILAR LA CLASE Presentacion,
y, si se conoce la referencia del objeto, SE PUEDE CAMBIAR
LA LÓGICA DEL NEGOCIO EN TIEMPO DE EJECUCIÓN
A. Goñi. Dpto. LSI, UPV/EHU
98
setGestorBilletes
(GestorBilletes) clase GestorBilletesImp
getBillete(String):int
// Implementada
Índice
• Introducción
• Arquitectura para JDBC. Tipos de
drivers
• Las clases e interfaces de JDBC
• Ejemplo de uso de JDBC: un servidor
de billetes
• Conexión con el nivel de presentación
Introducción
JDBC
• JDBC ofrece igual funcionalidad que ODBC
(Open Database Connectivity) de Microsoft
– El problema es que ODBC tiene interfaz C
• La gran mayoría de SGBD disponen ya de
drivers para trabajar con ODBC
• En el JDK se suministra un puente JDBC-
ODBC para convertir llamadas JDBC a
ODBC y poder acceder así a BDs que ya
tienen un driver ODBC mediante JDBC
– En el caso de hacerlo así, hay que registrar la BD
correspondiente para ser usada con ODBC
A. Goñi. Dpto. LSI, UPV/EHU
105
API de JDBC
APLICACIÓN Connection c;
Abrir Conexión BD 1 BD 1
Enviar/
Crear Statement Recibir
SQL
SGBD X
Cargar el Controlador/Driver
• Para cargar un controlador se puede usar el
método forName() de la clase Class (carga
clases Java)
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
– carga el puente JDBC-ODBC
Class.forName(“org.gjt.mm.mysql.Driver”);
– carga el Driver JDBC para trabajar con el SGBD
mySQL
• La clase java.lang.Class permite crear
instancias de clases en tiempo de ejecución:
Object o =
Class.forName(“org.gjt.mm.mysql.Driver”).newInstance();
– Crea una instancia de la clase
org.gjt.mm.mm.mysql.Driver y la asigna al objeto o
A. Goñi. Dpto. LSI, UPV/EHU
108
La clase DriveManager
• Sirve para registrar los controladores o drivers
DriverManager.registerDriver(
new sun.jdbc.odbc.JdbcOdbcDriver());
• No es necesario hacerlo si se ha cargado el Driver
con Class.forName
• Además puede establecer conexiones con BDs
Connection c = DriverManager.getConnection(
String dir,String usu,String clave)
– dir identifica a la BD. Dependiendo del SGBD
usado tendrá una forma u otra
jdbc:subprotocolo//servidor:puerto/base de datos
– usu y clave son nombre de usuario y clave, si hay
A. Goñi. Dpto. LSI, UPV/EHU
109
La interfaz Connection
La interfaz Connection
Interfaz Statement
• Sirve para enviar preguntas SQL a la BD
int i = s.executeUpdate(String sql);
// s contiene un objeto de Statement
ejecuta una sentencia SQL INSERT, UPDATE o
DELETE y devuelve el número de tuplas afectadas
ResultSet r = s.executeQuery(String sql);
ejecuta una sentencia SQL SELECT y devuelve el
resultado en un objeto ResultSet
Interfaz Statement
Interfaz ResultSet
• Sirve para trabajar con las respuestas a las
preguntas SQL realizadas
boolean b = r.next();
// r es un objeto de tipo ResultSet
se posiciona en la siguiente tupla del resultado; devuelve
true si hay o false si se ha llegado al final
• Existen métodos get que devuelven el valor de
la tupla actual correspondiente a un atributo de
la tabla respuesta.
– El atributo se puede identificar por el nombre dado
en la parte SELECT de la pregunta o por su
posición en la misma
– El tipo del atributo puede ser conocido o no
A. Goñi. Dpto. LSI, UPV/EHU
114
Interfaz ResultSet
String s = r.getString(numColumna);
String s = r.getString(nombreColumna);
int i = r.getInt(numColumna);
int i = r.getInt(nombreColumna);
boolean b = r.getBoolean(numColumna);
boolean b = r.getBoolean(nombreColumna);
// si conocemos el tipo del atributo
Object o = r.getObject(numColumna);
Object o = r.getObject(nombreColumna);
// si no conocemos el tipo del atributo
rs.next()
true
int i = rs.getInt(1);
1
String est = rs.getString(2);
OCUPADO
rs.next()
true
int i = rs.getInt(“NUMERO”);
0
String est = rs.getString(“ESTADO”);
OCUPADO
rs.next()
true
Object i = rs.getObject(1);
i.toString() “2”
String est = rs.getString(“ESTADO”);
LIBRE
rs.next()
false
4
Seleccionar una BD
Access previamente
creada
A. Goñi. Dpto. LSI, UPV/EHU
125
CREAR OBJETO
DE PRESENTACIÓN
ASIGNAR ESA
LÓGICA DEL NEGOCIO
AL OBJETO PRESENTACIÓN
A. Goñi. Dpto. LSI, UPV/EHU
131
setGestorBilletes
(GestorBilletes) clase ServidorGestorBilletesBD
getBillete(String):int
inicializarSala(int)
crearTablaBilletes()
4. Mecanismos de serialización en
Java
Serialización de objetos
CLASES OBJETOS
Persona juan:Persona elena:Persona
dni: int 17832423 17114452
nombre: String “Juan Pérez” “Elena Pérez”
suCoche: Coche coche1 coche1
Coche
coche1:Coche
matricula: String
modelo: String 3541 CGH
susProp: Vector “Citroen C4”
<juan,elena>
Serialización de objetos
Serialización de objetos
throws IOException;
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
A. Goñi. Dpto. LSI, UPV/EHU
138
Serialización de objetos
por la red …
ObjectOutputStream socketComoStream =
new ObjectOutputStream (socket.getOutputStream());
socketComoStream.writeObject(juan);
socketComoStream.writeObject(elena);
setGestorBilletes
(GestorBilletes) clase ServidorGestorBilletesSerializado
getBillete(String):int
inicializarSala(int)
escribir()
leer()
A. Goñi. Dpto. LSI, UPV/EHU
Nueva lógica del negocio para144 el
ejemplo de PEDIR BILLETES.
Se pide el billete a un servidor
(que se encuentra en la máquina
“host”) por medio de un
SOCKET. Se usan mecanismos
de SERIALIZACIÓN para el
paso de parámetros y recogida
de resultados.
setGestorBilletes
clase GestorBilletesCliente
(GestorBilletes)
getBillete(String):int
En distintos ordenadores
5. Introducción a la
computación distribuida con
Java RMI
Introducción a RMI
Introducción a RMI
Clase GestorBilletes
Clase Cliente1
.... - listaBilletes: Vector
- maxBilletes: int
+ getGestor(): GestorBilletes
+ getBillete(nom: String): int
Clase ClienteN // Dev. nº billete asignado o -1 si no hay
....
-- Clase con 1 sola instancia (Singleton)
-- El método static getGestor() la devuelve
EN NODOS CLIENTE EN EL NODO SERVIDOR
No es posible realizar lo siguiente en una clase cliente:
GestorBilletes g = GestorBilletes.getGestor();
return g.getBillete("Kepa Sola");
Introducción a RMI
Interfaz remota
Interfaz GestorBilletes
Cliente1
....
Interfaz Remota
// GestorBilletes.java
import java.rmi.*;
public interface GestorBilletes
extends Remote
{
Interfaz java.rmi.Remote
public int getBillete(String nom)
throws RemoteException;
-- INTERFAZ REMOTA
}
Servidor Remoto
Clase java.rmi.server.UnicastRemoteObject Interfaz java.rmi.Remote
extiende extiende
Clase ServidorGestorBilletes implementa Interfaz GestorBilletes
+ getBillete(nom: String): int + getBillete(nom: String): int
-- CLASE REMOTA -- INTERFAZ REMOTA
Servidor Remoto
// Método main de ServidorGestorBilletes.java
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try {
ServidorGestorBilletes objetoServidor =
new ServidorGestorBilletes();
Cliente
Clase java.rmi.server.UnicastRemoteObject Interfaz java.rmi.Remote
extiende extiende
Clase ServidorGestorBilletes implementa Interfaz GestorBilletes
+ getBillete(nom: String): int + getBillete(nom: String): int
-- CLASE REMOTA -- INTERFAZ REMOTA
La clase cliente:
usa
• busca el objeto remoto que le proporciona
el servicio que le interesa. Para ello debe
Clase Cliente
conocer el nombre del servicio, pero no la ges : GestorBilletes
clase remota (no hace new) -- CLASE CLIENTE
• pide a dicho objeto que ejecute un método
remoto (definido en la interfaz remota)
A. Goñi. Dpto. LSI, UPV/EHU
158
//
Cliente
Cliente.java
import java.rmi.*;
try {
objRemoto = (GestorBilletes)Naming.lookup(nomServ);
int b = objRemoto.getBillete(args[0]);
if (b==-1) System.out.println("No hay billetes");
else System.out.println("Obtenido : "+b);
} catch (Exception e) { System.out.println("Error... ");}}}
A. Goñi. Dpto. LSI, UPV/EHU
159
Arquitectura RMI
objRemoto.getBillete("Koldo") objRemoto @ObjLocalX
RETURN: 5
Máquina virtual java CLIENTE
Arquitectura RMI
Programa Cliente Programa Servidor
call return call return
Stub Skeleton
Nivel de Nivel de
Referencia Remota Referencia Remota
Nivel de Nivel de
Transporte Transporte
Conexión TCP/IP
Los objetos Stub y Skeleton se
encargan de realizar la conexión y del
paso de parámetros y resultados.
A. Goñi. Dpto. LSI, UPV/EHU
162
Arquitectura RMI
GestorBilletes objRemoto =
(GestorBilletes)Naming.lookup("rmi://IPServidor/gestorBilletes");
lookup BUSCA y
objRemoto.getBillete("Koldo");
OBTIENE el objeto STUB
rmic ServidorGestorClientes
SE OBTIENEN LAS CLASES:
ServidorGestorClientes_Stub.class
ServidorGestorClientes_Skeleton.class
El fichero ServidorGestorClientes_Stub.class
debe quedar accesible a la máquina cliente. Una posibilidad
es copiarlo en ella (ver otra posibilidad más adelante...)
Arquitectura RMI
GestorBilletes objRemoto =
(GestorBilletes)Naming.lookup("rmi://IPServidor/gestorBilletes");
¿Cómo se sabe cuál es la clase STUB de la cual
hay que crear un objeto?
GestorBilletes es un interface
La clase en este caso es
ServidorGestorBilletes_Stub.class
....
....
Naming.rebind("gestorBilletes",objetoServidor);
A. Goñi. Dpto. LSI, UPV/EHU
165
rmiregistry
• Es un servidor de nombres que relaciona
objetos con nombres
• Hay que lanzarlo como proceso independiente
en la máquina servidor
– En la misma máquina que el servidor RMI
• En Unix
– rmiregistry & (en Unix)
– rmiregistry numPuerto &
• En Windows
– rmiregistry [num. puerto]
– start rmiregistry [num. puerto]
A. Goñi. Dpto. LSI, UPV/EHU
166
rmiregistry
Serialización de
parámetros/resultados
• En principio, los stubs y los servidores RMI se
pasan los objetos enviados como parámetros y
los resultados REALIZANDO UNA COPIA DE
SUS VALORES (y de los objetos incluidos en
ellos, recursivamente).
– No se pasan referencias a un objeto remoto.
• Para ello, se usan los mecanismos de
serialización de Java
las clases de dichos objetos deben
implementar la interfaz Serializable
stub: ServidorGestorBilletesBD
Rmiregistry rebind("localhost:1099/gestorBilletes",objRemoto)
_Stub
getRef()
new(referenciaAObjRemoto)
referenciaAObjRemoto
: PedirBillete
Naming SOCKET("localhost",1099,"gestorBilletes",stub)
lookup("rmi://IpServidor:1099/gestorBilletes")
SOCKET("IPservidor",1099,"gestorBilletes") Se pasa el objeto STUB serializado.
El cliente cargará dinámicamente la clase
ServidorGestorBilletesBD_Stub
SOCKET(stub)
stub
stub: ServidorGestorBilletesBD
_Stub
getBillete("Pepe")
SOCKET("IPServidor",PuertoAnonimo,"gestorBilletes","getBillete","Pepe")
numBilleteParaPepe
SOCKET(numBilleteParaPepe)
java.security.policy
• Un programa Java debe especificar un gestor
de seguridad que determine su política de
seguridad.
• Algunas operaciones requieren que exista
dicho gestor. En concreto, las de RMI.
– RMI sólo cargará una clase serializable desde otra
máquina si hay un gestor de seguridad que lo
permita
– Se puede establecer un gestor de seguridad por
defecto para RMI de la siguiente manera:
System.setSecurityManager(
new RMISecurityManager());
A. Goñi. Dpto. LSI, UPV/EHU
170
java.security.policy
• El gestor de seguridad por defecto de RMI
utiliza una política muy restrictiva.
– Sólo se pueden ejecutar STUBs del CLASSPATH local
• Se puede cambiar, indicando a la máquina
virtual Java otro fichero de política de
seguridad:
java -Djava.security.policy=java.policy Clase
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:Bill");
sentencia=conexion.createStatement();
conexion.setAutoCommit(false);// Habrá que hacer COMMITs
} catch(Exception e)
{ System.out.println(”Error: "+e.toString());} }
A. Goñi. Dpto. LSI, UPV/EHU
173
Servidor Remoto accede a BD
public int getBillete(String nom)
throws RemoteException {
// Devuelve nº billete, -1 si no hay, -2 si hay problemas
String pregSQL = "SELECT NUM FROM BILLETES”+
" WHERE ESTADO='LIBRE'";
try{ ResultSet rs = sentencia.executeQuery(pregSQL);
if (rs.next()) {
String num = rs.getString("NUM");
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = '"+nom+
"' WHERE NUM="+num+" AND ESTADO='LIBRE'");
conexion.commit();
int n= Integer.parseInt(num);
if (act>0) return n; // Núm. billete asignado
return -2; } // Otro ya ha OCUPADO ese billete
else return -1; } // No había ninguno libre
catch (SQLException e)
{System.out.println("Error: "+e.toString());}
return -2; // Que prueben otra vez a llamar
} A. Goñi. Dpto. LSI, UPV/EHU
174
Servidor Remoto accede a BD
// Método main de ServidorGestorBilletesBD.java
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try {
ServidorGestorBilletesBD objetoServidor =
new ServidorGestorBilletesBD();
setLogicaNegocio
clase LogicaNegocioConcreta
(l: LogicaNegocio)
// Permite cambiar lógica hacerX(…) // Implementaciones
// negocio en tº ejecuc. hacerY(…) // llaman al nivel de
-- En esta clase se llama // datos (usan JDBC)
-- a la lógica del negocio:
Por ej.: logNe.hacerX(…)
CREAR LA INTERFAZ GRÁFICA Y ASIGNAR LÓGICA DEL NEGOCIO:
Presentacion p = new Presentacion();
p.setLogicaNegocio(new LogicaNegocioConcreta());
p.setVisible(true);
A. Goñi. Dpto. LSI, UPV/EHU
177
ARQUITECTURA FÍSICA Interface LogicaNegocio
EN 3 NIVELES
usando RMI hacerX(… )
hacerY(… )
Clase Presentacion
usa interfaz Remota
logNe: LogicaNegocio
setLogicaNegocio
clase LogicaNegocioConcreta
(String nombreServicio)
// Por ejemplo aquí se hacerX(…) // Implementaciones
// puede asignar a logNe hacerY(…) // llaman al nivel de
-- En esta clase se llama // datos (usan JDBC)
-- a la lógica del negocio:
-- La lógica del negocio se crea
Por ej.: logNe.hacerX(…)
-- y se exporta usando:
-- Para asignar la lógica
Naming.rebind y dando un
-- del negocio se usa
nombre de servicio: NomSer
Naming.lookup y NomSer
A. Goñi. Dpto. LSI, UPV/EHU
178
Índice
• Introducción
• Applets
– Introducción y algunas características
técnicas
– Nivel de presentación con Applets
– Nivel de lógica del negocio con Applets
• Servlets
• Java Server Pages (JSPs)
– Introducción y algunas características
técnicas
– Nivel de presentación con JSPs
– Nivel de lógica del negocio con JSPs
A. Goñi. Dpto. LSI, UPV/EHU
180
Introducción
Introducción
Applets
Cliente
Navegador
Applet
Ejecución de applets
Ejecución de applets
<html><head><title>Applet1</title></head><hr>
<hr></body></html>
A. Goñi. Dpto. LSI, UPV/EHU
187
Nivel de presentación usando
Applets
Usando Appletviewer
A. Goñi. Dpto. LSI, UPV/EHU Usando un navegador
192
¿Validar la entrada es nivel de
presentación o lógica del negocio?
• Validar la entrada tiene que ver con la
presentación, con la interacción con el usuario,
que ha escrito mal los datos: debe hacerse en
el nivel de presentación
• Sin embargo, a veces no está tan clara la
diferencia entre nivel de presentación y lógica
del negocio
• En una aplicación Web no importa tanto, ya
que el nivel de presentación “se instala” en el
lado del servidor y se ejecuta en los clientes.
Cambiar la lógica del negocio o presentación
NO requiere reinstalar los clientes
• Regla a observar: intuir cambios futuros y
hacer el software extensible ante esos cambios
A. Goñi. Dpto. LSI, UPV/EHU
193
Servlets
Html
Servlet
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ServletTemplate extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// En "request" se leen las cabeceras HTTP y los
// datos que se hayan escrito en formularios
// Se usa "response" para especificar el código de
// estado de la respuestas y las cabeceras HTTP (ej.
// tipo del contenido, cookies, etc.)
PrintWriter out = response.getWriter();
// Se usa "out" para enviar el contenido al navegador
}
}
A. Goñi. Dpto. LSI, UPV/EHU
195
Ejemplo de Servlet
public class HolaWWW extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String docType =
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
"Transitional//EN\">\n";
out.println(docType +
"<HTML>\n" +
"<HEAD><TITLE>Hola WWW</TITLE></HEAD>\n" +
"<BODY>\n" +
"<H1>Hola WWW</H1>\n" +
"</BODY></HTML>");}}
JSP
Html <HTML>
%%Java
</HTML>
Scriptlet JSP
Scriptlet JSP
<html><body>
<H1> Ejemplo de código Java incrustado </H1><P>
<%
for (int i=0;i<3;i++)
out.println("<H2> Hola número "+i+"</H2><BR>");
%>
<P>
<H1> Adiós </H1>
</body></html>
JSP Expression
• <%= expression %>
– Expresión que se evalúa y se coloca en la salida
– Se usan variables predefinidas: request,
response, out, session, application, config, y
pageContext
<html><body>
<H1> Ejemplo de código Java incrustado </H1><P>
<%
for (int i=0;i<3;i++){
%><H2> Hola número <%=i%></H2><BR><%}
%>
<P>
<H1> Adiós </H1>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
200
Expresión JSP
<html><body>
<H1> Ejemplo de código Java incrustado </H1><P>
<%
for (int i=0;i<3;i++){
%><H2> Hola número <%=i%></H2><BR><%}
%>
<P>
<H1> Adiós </H1>
</body></html>
Declaración JSP
Declaración JSP
<html><body>
<H1> Ejemplo de código Java incrustado </H1><P>
<%! int i=0; %>
<%
for (int j=i;j<i+3;j++){
%><H2> Hola número <%=j%></H2><BR><%}
i=i+3;
%>
<P> <H1> Adiós </H1>
</body></html>
Primera ejecución
del JSP
Segunda ejecución
del JSP
A. Goñi. Dpto. LSI, UPV/EHU
203
Comentarios JSP
Mi afición preferida:
<SELECT NAME="aficion">
<OPTION VALUE="monte"> Ir al monte
<OPTION VALUE="bailar"> Bailar
<OPTION VALUE="estudiar" SELECTED>Estudiar
</SELECT>
<P>
Cuéntame tu vida:
<TEXTAREA NAME="vida"
ROWS=15 COLS=60 WRAP="SOFT"></TEXTAREA>
<INPUT TYPE="SUBMIT" value="Enviar datos"> <!--
Pulsar aquí para enviar los datos -->
</CENTER>
</FORM>
A. Goñi. Dpto. LSI, UPV/EHU
209
request.
getParameter
("PARAM")
A. Goñi. Dpto. LSI, UPV/EHU
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 211
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date(); MOSTRAR
int numAccesos = 0;
%> LA SALIDA
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img> CON HTML
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- Comentario HTML: aparece como comentario en el HTML, pero no se verá en el
navegador del cliente. A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 212
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date();
int numAccesos = 0;
%>
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img>
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer.
Este comentario se verá en el navegador del cliente --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 213
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date();
int numAccesos = 0;
%>
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img>
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer.
Este comentario se verá en el navegador del cliente --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
También se puede validar la entrada 214
en el nivel de presentación con JSPs y
JavaScript
• Más eficiente: sólo se llama a la lógica
del negocio con entradas correctas
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<TITLE>PEDIR BILLETE</TITLE></HEAD>
<BODY>
<H1> PEDIR BILLETE </H1>
<FORM NAME="LE" METHOD="post" ACTION="PedirBillete.jsp">
Nombre: <INPUT TYPE="text" NAME="nombre" onChange=validar();><P>
<INPUT TYPE="submit" value="Pedir Billete" >
<INPUT type="reset" VALUE="Borrar Datos">
</FORM>
<SCRIPT LANGUAGE="JavaScript">
function validar()
{var nombre = document.LE.nombre.value;
if (nombre.length<5) alert("Error, menos de 5 letras:" +
document.LE.nombre.value);
document.LE.nombre.value = ""; }
</SCRIPT></BODY></HTML>
A. Goñi. Dpto. LSI, UPV/EHU
215
Java Beans
Instanciar JavaBeans
Instanciar JavaBeans
<jsp:useBean id="gestorBilletes"
class="beans.GestorBilletesBean"
scope="application" />
Crea o encuentra la instancia de la clase beans.GestorBilletesBean,
accesible durante “toda la aplicación”, y la que podrá referirse con el
identificador gestorBilletes
<%! gestorBilletes =
new beans.GestorBilletesBean(); }
CUIDADO, NO ES EXACTAMENTE EQUIVALENTE…
CON scope=“request” cada vez se crea una instancia nueva
Llamar a JavaBeans
<jsp:useBean id="gestorBilletes"
class="beans.GestorBilletesBean"
scope="request" />
• A partir de ese momento se puede usar el
bean, directamente en Java:
<%
...
int res =
gestorBilletes.getBillete(nombre);
...
%>
A. Goñi. Dpto. LSI, UPV/EHU
221
• <jsp:setProperty att=val*/>
– Para poner valores en atributos del Java Bean.
• name=“identificador del bean"
• property=“nombre del atributo|*"
• param=“nombre del parámetro de formulario"
• value=“valor a asignar"
<jsp:setProperty name="gestorBilletes"
property="nombre" value="Pepe" />
Equivalente a:
<% gestorBilletes.setNombre(“Pepe”);%>
<jsp:setProperty name="gestorBilletes"
property="nombre" param="nom" />
Equivalente a:
<% String s1 = request.getParameter("nom");
gestorBilletes.setNombre(s1);%>
A. Goñi. Dpto. LSI, UPV/EHU
222
<jsp:getProperty name="gestorBilletes"
property="nombre" />
Equivalente a:
<%= gestorBilletes.getNombre();%>
package beans;
import java.sql.*;
public class GestorBilletesBean
{
public GestorBilletesBean() {
try{
Class.forName("org.gjt.mm.mysql.Driver");
conexion=DriverManager.getConnection
("jdbc:mysql://localhost/Billetes");
… }
public int getBillete(String nom) {
String pregSQL = "SELECT NUMERO FROM BILLETES"+
" WHERE ESTADO='LIBRE'";
try{
ResultSet rs = sentencia.executeQuery(pregSQL);
..}}
A. Goñi. Dpto. LSI, UPV/EHU
227
Otra posibilidad: añadir otro nivel en
la propia lógica del negocio
Más información…
Índice
• Introducción
• HTTP en 5 minutos
• XML en 5 minutos
• SOAP
• WSDL
• Usar Servicios Web en JDeveloper
• Otros temas
• Un Servicio Web es
– (Parte de) Lógica de negocio
• La interfaz se define en un estándar basado en
XML (WSDL)
– Accesible mediante protocolos de Internet
• Habitualmente HTTP y SOAP (XML)
A. Goñi. Dpto. LSI, UPV/EHU
232
Lenguaje JAVA
Interfaces definidas en JAVA
Varias máquinas y S.O.
CORBA
RMI IIOP
JRMP / IIOP CLIENTE
TCP/IP SERVIDOR
CLIENTE
TCP/IP SERVIDOR Varios lenguajes: Java, C++…
Interfaces definidas en IDL
Varias máquinas y S.O.
Varios lenguajes .NET: C++, C#, . NET Remoting
VB.NET …
Interfaces definidas en .NET
(Sustituye a
Máquinas Windows (?) CLIENTE DCOM)
A. Goñi. Dpto. LSI, UPV/EHU SERVIDOR
233
HTTP en 5 minutos
Respuesta
Ejemplos de respuestas:
Ejemplos de comandos en peticiones:
Estados
GET Para leer una página Web
Datos
POST: Para enviar datos a una página Web
Códigos de error
HTTP en 5 minutos
HTTP en 5 minutos
[85] sisf00 > telnet sipx55.si.ehu.es 8080 Con telnet se puede abrir un socket
Trying 158.227.112.155... interactivo con un servidor HTTP
Connected to sipx55.si.ehu.es.
Escape character is '^]'.
Con GET se solicita una página web
GET /iso/jsp/public_html/pagina.jsp HTTP/1.0
(en este caso es un JSP)
// Añadir línea en blanco
HTTP/1.0 200 OK
Content-Type: text/html;charset=windows-1252
Set-Cookie2: JSESSIONID=pjqb72fy21;Version=1;Discard;Path="/iso"
Set-Cookie: JSESSIONID=pjqb72fy21;Path=/iso
Servlet-Engine: Tomcat Web Server/3.2.3 (JSP 1.1; Servlet 2.2; Java 1.3.1_02;
Windows 2000 5.0 x86; java.vendor=Sun Microsystems Inc.)
HTTP en 5 minutos
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Prueba</title>
</head>
<body>
<h2> Hola Alfredo<br>
Estamos a: Tue May 03 14:11:01 CEST 2005
</h2>
</body>
</html>
Connection closed by foreign host.
[108] sisf00 >
A. Goñi. Dpto. LSI, UPV/EHU
238
XML en 5 minutos
XML en 5 minutos
ENCABEZAMIENTO XML: VERSIÓN Y
CONJUNTO DE CARACTERES
ETIQUETAS: se deben abrir y cerrar
<nombreSala> …</nombreSala>
OBLIGATORIO UN ÚNICO ELEMENTO
RAÍZ: <entradasTodasSalas>
ATRIBUTOS (siempre entre comillas, simples o dobles):
<sala imagen=“principe1.gif”>
XML en 5 minutos
En un navegador
se puede ver el
fichero XML;
abrir y cerrar
“etiquetas”
A. Goñi. Dpto. LSI, UPV/EHU
241
Documentos XML bien formados vs.
Documentos XML válidos
• Un documento XML está bien formado si cumple
las restricciones anteriores
– No hay nodo raíz, atributos no entre comillas,
mal anidamiento, etc…
• Pero es posible que no sea un documento XML
válido
– Nombres de etiquetas, atributos erróneos
– No aparición de alguna etiqueta obligatoria
–…
• Se puede definir la estructura de un documento
XML usando DTD o XML-Schema
• Qué etiquetas deben/pueden venir, qué
atributos, en qué orden, etc.
A. Goñi. Dpto. LSI, UPV/EHU
242
Llamadas a servicios remotos
usando XML y HTTP
Se puede definir una
estructura de documento
XML que describa una
llamada a un procedimiento
remoto
XML
HTTP
Se usa HTTP para la
transmisión de datos XML
CLIENTE entre las aplicaciones
CLIENTE y SERVIDOR
SERVIDOR
XML
HTTP
Se usa HTTP para la
CLIENTE transmisión de datos XML
entre las aplicaciones SERVIDOR
CLIENTE y SERVIDOR
SOAP Envelope
El mensaje se mete en un sobre (envelope)
SOAP header El mensaje se compone de una cabecera (header)
Bloque Header OPCIONAL y de un cuerpo (Body)
OBLIGATORIO
Bloque Header
La cabecera (header) se utiliza para enviar
SOAP Body información sobre identificadores de
Bloque Body transacciones, certificados de seguridad,
información sobre coordinación, etc.
Bloque Body
getNumBillete(“Pepe”)
Resultado de la llamada a
getNumBillete(“Pepe”)
==> 2 (como int)
A. Goñi. Dpto. LSI, UPV/EHU
248
Se necesita un estándar que
describa el Servicio Web
Message MENSAJES DE
ABSTRACTA
PARA CADA
Operation 1 Operation 2
OPERACIÓN
SERVICIO ABSTRACTO
Interface (CONJUNTO DE
OPERACIONES)
DEL SERVICIO
DESCRIPCIÓN
CONCRETA
ENLACES A PROTOCOLOS
binding 1 binding 2 binding 3 DE TRANSPORTE
DIRECCIONES DE LOS
endpoint 1 endpoint 2 endpoint 3 ENLACES
TODAS LAS
IMPLEMENTACIONES DEL
Service
A. Goñi. Dpto. LSI, UPV/EHU SERVICIO
251
WSDL
Types
Operation 1 Operation 2
Interface
RESULTADO
Mensaje
SOAP con la
respuesta
A. Goñi. Dpto. LSI, UPV/EHU
260
Usar SW en JDeveloper
Crear un SW en Java
Punto
acceso
Ejecutamos el SW
Ejecutamos el
cliente del SW
Otros temas
Ejercicio de Arquitecturas
Software
Solución
Precios
inicializarBD(): void
getPrecio(nombre:String): float
calcularPrecio(kgMan,kgPer,kgNar: String) : float
void button1_actionPerformed(ActionEvent e) {
// En p tenemos el objeto con la lógica del negocio
float precio = p.calcularPrecio(textField1.getText(),
textField2.getText(),
textField3.getText());
Aviso a = new Aviso(this,"Precio es: "+precio);
}
Precios
inicializarBD(): void
getPrecio(nombre:String): float
getPrecioMan(): float
getPrecioPer(): float,
getPrecioNar(): float
A. Goñi. Dpto. LSI, UPV/EHU
287
LA LÓGICA DEL NEGOCIO SE USA DESDE EL
MÉTODO DE ATENCIÓN AL EVENTO
void button1_actionPerformed(ActionEvent e) {
// En pr tenemos el objeto con la lógica del negocio
String kgManz = textField1.getText(); // idem. kgPer y KgNar
try{m=Float.parseFloat(kgManz);} catch (Exception ex) {m=0;}
try{p=Float.parseFloat(kgPer);} catch (Exception ex) {p=0;}
try{n=Float.parseFloat(kgNar);} catch (Exception ex) {n=0;}
float precio = m*pr.getPrecioMan()+ p*pr.getPrecioPer() +
n*pr.getPrecioNar();
Aviso a = new Aviso(this,"Precio es: "+precio);}
NO ES EXTENSIBLE. EL PRECIO DE LOS
PRODUCTOS NO DEPENDE DE LA CANTIDAD.
HABRÍA QUE CAMBIAR LA PRESENTACIÓN:
if (m>10) precioMan = pr.getPrecioMan()*0.9;
// idem. con resto de productos y descuentos
A. Goñi. Dpto. LSI, UPV/EHU
288
Precios
inicializarBD(): void
getPrecio(nombre:String): float
calcularPrecio(PrecCant:Enumeration ) : float
obtenerProductos(): Enumeration
A. Goñi. Dpto. LSI, UPV/EHU