Download arquitecturas software de varios niveles en java

Document related concepts
no text concepts found
Transcript
1
INGENIERÍA del SOFTWARE
Curso 2006/07
Ingeniería en Informática
Facultad de Informática
UPV/EHU
Departamento de Lenguajes
y Sistemas Informáticos
A. Goñi. Dpto. LSI, UPV/EHU
2
Tema 2:
Arquitecturas Software de varios
niveles en Java
A. Goñi. Dpto. LSI, UPV/EHU
3
Í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
A. Goñi. Dpto. LSI, UPV/EHU
5
Í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
• Algunas aplicaciones deben soportar a varios
usuarios que de manera concurrente, segura, fiable y
eficiente ejecutan varias operaciones.
• Ejemplos:
– bancos con cajeros conectados a un servidor central
– distribuidores de ventas al por menor
– terminales donde se pueden comprar entradas para
espectáculos
• En estos casos es útil una arquitectura con
despliegue de componentes software en el lado
del servidor (server side component architecture)
– Componente: código que implementa un conjunto
conocido de interfaces
A. Goñi. Dpto. LSI, UPV/EHU
Ejemplo: comprar billetes para
espectáculos
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
7
8
public class PedirBilleteNO3NIVELES extends JFrame {
// Nota: NO ESTÁ COMPLETA !!
JLabel jLabel1 = new JLabel(“Nombre:”);
JButton jButton1 = new JButton(“Pedir Billete”);
public PedirBilleteNO3NIVELES() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes"); }
void jButton1_actionPerformed(ActionEvent e) {
ResultSet rs = sentencia.executeQuery("SELECT NUMERO FROM"+
" BILLETES WHERE ESTADO=\'LIBRE\'");
if (rs.next()) {
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = "+jTextField1.getText()+
" WHERE NUMERO="+rs.getString("NUMERO")+
" AND ESTADO='LIBRE'");
if (act>0) jTextArea1.append("Asignado. \nReferencia: "+n+"\n");
else jTextArea1.append("Error al asignar billete"); }}
public static void main (String []arg) {
PedirBilleteNO3NIVELES b = new PedirBilleteNO3NIVELES();
A. Goñi. Dpto. LSI, UPV/EHU
b.setVisible(true);}}
9
public class PedirBilleteNO3NIVELES extends JFrame {
// Nota: NO ESTÁ COMPLETA !!
JLabel jLabel1 = new JLabel(“Nombre:”);
JButton jButton1 = new JButton(“Pedir Billete”);
public PedirBilleteNO3NIVELES() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes"); }
void jButton1_actionPerformed(ActionEvent e) {
ResultSet rs = sentencia.executeQuery("SELECT NUMERO FROM"+
" BILLETES WHERE ESTADO=\'LIBRE\'");
if (rs.next()) {
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = "+jTextField1.getText()+
" WHERE NUMERO="+rs.getString("NUMERO")+
" AND ESTADO='LIBRE'");
if (act>0) jTextArea1.append("Asignado. \nReferencia: "+n+"\n");
else jTextArea1.append("Error al asignar billete"); }}
PRESENTACIÓN
public static void main (String []arg) {
PedirBilleteNO3NIVELES b = new PedirBilleteNO3NIVELES();
A. Goñi. Dpto. LSI, UPV/EHU
b.setVisible(true);}}
10
public class PedirBilleteNO3NIVELES extends JFrame {
// Nota: NO ESTÁ COMPLETA !!
JLabel jLabel1 = new JLabel(“Nombre:”);
JButton jButton1 = new JButton(“Pedir Billete”);
public PedirBilleteNO3NIVELES() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes"); }
void jButton1_actionPerformed(ActionEvent e) {
ACCESO A
DATOS
ResultSet rs = sentencia.executeQuery("SELECT NUMERO FROM"+
" BILLETES WHERE ESTADO=\'LIBRE\'");
if (rs.next()) {
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = "+jTextField1.getText()+
" WHERE NUMERO="+rs.getString("NUMERO")+
" AND ESTADO='LIBRE'");
if (act>0) jTextArea1.append("Asignado. \nReferencia: "+n+"\n");
else jTextArea1.append("Error al asignar billete"); }}
public static void main (String []arg) {
PedirBilleteNO3NIVELES b = new PedirBilleteNO3NIVELES();
A. Goñi. Dpto. LSI, UPV/EHU
b.setVisible(true);}}
LÓGICA DEL NEGOCIO
public class PedirBilleteNO3NIVELES extends JFrame {
// Nota: NO ESTÁ COMPLETA !!
JLabel jLabel1 = new JLabel(“Nombre:”);
JButton jButton1 = new JButton(“Pedir Billete”);
public PedirBilleteNO3NIVELES() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes"); }
void jButton1_actionPerformed(ActionEvent e) {
ResultSet rs = sentencia.executeQuery("SELECT NUMERO FROM"+
" BILLETES WHERE ESTADO=\'LIBRE\'");
if (rs.next()) {
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = "+jTextField1.getText()+
" WHERE NUMERO="+rs.getString("NUMERO")+
" AND ESTADO='LIBRE'");
if (act>0) jTextArea1.append("Asignado. \nReferencia: "+n+"\n");
else jTextArea1.append("Error al asignar billete"); }}
public static void main (String []arg) {
PedirBilleteNO3NIVELES b = new PedirBilleteNO3NIVELES();
A. Goñi. Dpto. LSI, UPV/EHU
b.setVisible(true);}}
11
12
Arquitectura lógica del
software en niveles
ES MEJOR SEPARAR EL CÓDIGO EN
NIVELES: USAR CLASES DISTINTAS
NIVEL DE
PRESENTACIÓN
Nombre:
Pedir Billete
NIVEL DE LÓGICA
DEL NEGOCIO
NIVEL DE
DATOS
public class GB
implements GestorBilletes {
...
public Billete getBillete
(String nom) {...}
SELECT ...
INSERT ...
CLASES CON OPERACIONES
PROPIAS DEL NEGOCIO
INTERFAZ GRÁFICO DE
USUARIO:
Frame o Applet
- inicializarSala
- getBillete,...
BASE DE DATOS
A. Goñi. Dpto. LSI, UPV/EHU
Aquí se pueden aplicar reglas del
negocio: por cada 10 billetes
comprados se regala uno, etc...
Arquitectura lógica del
software en niveles
13
• NIVEL DE PRESENTACIÓN
– contiene componentes que implementan las interfaces
de usuario y la interacción con el mismo
– se construye mediante clases (ej: Frames, Applets),
páginas HTML, JSPs,…
• NIVEL DE LÓGICA DEL NEGOCIO
– contiene componentes que resuelven los problemas
del negocio; proporciona servicios u operaciones que
implementan las reglas propias del negocio.
– se construye mediante clases Java con los
servicios/operaciones de la lógica del negocio
• Se consigue más extensibilidad si la lógica del negocio se
define mediante interfaces Java.
• NIVEL DE DATOS
– utilizado por el nivel lógica del negocio para conseguir
la persistencia de datos. Es una o más BDs.
A. Goñi. Dpto. LSI, UPV/EHU
14
Arquitectura lógica del
software en niveles
• Ventaja: AISLAR UN NIVEL DE LOS OTROS
– Se puede cambiar el nivel de presentación minimizando
los cambios en los niveles de lógica del negocio y de
datos
– Se puede cambiar alguna de las reglas del negocio con
pocos cambios en el resto
– Se puede cambiar la base de datos con pocos cambios
en el resto
UNA ARQUITECTURA LÓGICA DEL SOFTWARE EN
VARIOS NIVELES FAVORECE LA EXTENSIBILIDAD
Y REUTILIZACIÓN DEL SOFTWARE
A. Goñi. Dpto. LSI, UPV/EHU
15
El análisis y diseño de los casos de uso
seguía una filosofía en varios niveles…
A. Goñi. Dpto. LSI, UPV/EHU
Los diagramas de colaboración
(análisis) del PUD siguen filosofía 3
niveles
NIVEL DE
PRESENTACIÓN
NIVEL DE
DATOS
NIVEL DE LÓGICA
DEL NEGOCIO
A. Goñi. Dpto. LSI, UPV/EHU
16
17
Los diagramas de colaboración (análisis)
del PUD siguen filosofía 3 niveles
NIVEL DE PRESENTACIÓN
• Clases FRONTERA
representan
• Clases CONTROL
NIVEL DE LÓGICA DEL NEGOCIO
representan
NIVEL DE DATOS
• Clases ENTIDAD
representan
A. Goñi. Dpto. LSI, UPV/EHU
Y también los de secuencia (diseño)
18
Lógica del Negocio
: Usuario
: PedirBillete
: GestorBilletes
: GestorBD
Proporcionar nombre y solicitar billete
Datos
getBillete(nombre)
executeQuery:=executeQuery( P1)
: ResultSet
new()
Presentación
next()
next()
[hay libres] : get("NUMERO")
num
executeUpdate:=executeUpdate(P2)
b : Billete
new(num, nom)
[no hay libres]: new(-1, "")
b
A. Goñi. Dpto. LSI, UPV/EHU
Arquitectura física del
software en niveles
19
• La separación FÍSICA de los niveles lógicos
admite distintas posibilidades:
• Arquitectura en 2 niveles físicos
– 2 de los niveles se juntan en un nodo
– 2 posibilidades:
• la lógica del negocio se junta con la presentación
• parte de la lógica del negocio se junta con los datos
• Arquitectura en 3 niveles físicos
– Cada nivel lógico en un nodo distinto
• Aplicaciones de más niveles físicos
– nivel de presentación instalado en el servidor
Web y ejecutado en cliente (navegador Web)
A. Goñi. Dpto. LSI, UPV/EHU
20
Arquitectura física en 2 niveles:
cliente gordo/servidor flaco
• El nivel de presentación y el de la lógica
del negocio se unen en un nodo.
En el otro queda el nivel de datos.
CLIENTE
NIVEL DE
PRESENTACIÓN
NIVEL DE LÓGICA
DEL NEGOCIO
SERVIDOR
NIVEL DE
DATOS
• Comunicación entre Cliente y Servidor en SQL
• Se necesitan APIs como por ejemplo JDBC y/o ODBC
• Deben instalarse DRIVERS de la BD en todos los clientes
A. Goñi. Dpto. LSI, UPV/EHU
21
CLIENTE
public class PedirBillete2NivCliGordo extends JFrame {
GestorBilletes2NivCliGordo gestorBilletes;
Presentación
void jButton1_actionPerformed(ActionEvent e) {
int res = gestorBilletes.getBillete(jTextField1.getText()).getNum();
if (res<0) jTextArea1.append("Error al asignar billete");
else jTextArea1.append("Asignado. \nReferencia: "+res+"\n");} }
Lógica del Negocio
public class GestorBilletesBD
implements GestorBilletes2NivCliGordo
{ public GestorBilletesBD() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
public Billete getBillete(String nom)
{ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
int act = sent.executeUpdate("UPDATE BILLETES …“);
if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
INSTALAR LA CLASE sun.jdbc.odbc.JdbcOdbcDriver
Y DEFINIR FUENTE DATOS ODBC “Billetes”
A. Goñi. Dpto. LSI, UPV/EHU
BD
Datos
SERVIDOR
22
CLIENTE
Sentencia SQL
CLIENTE
Respuesta
CLIENTE
CLIENTE
BD
Driver
CLIENTE
CLIENTE
dbcDriver
CLIENTE
OdbcDriver
CLIENTE
CLIENTE
c.JdbcOdbcDriver
CLIENTE
CLIENTE
bc.JdbcOdbcDriver
SERVIDOR
CLIENTE
bc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE
n.jdbc.odbc.JdbcOdbcDriver
CLIENTE
¡¡ CADA CLIENTE
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver
sun.jdbc.odbc.JdbcOdbcDriver
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver
sun.jdbc.odbc.JdbcOdbcDriver
A. Goñi. Dpto. LSI, UPV/EHU
UNA CONEXIÓN
ABIERTA CON LA
BD!!
23
Arquitectura física en 2 niveles:
cliente gordo/servidor flaco
• El despliegue de la aplicación es alto: instalar drivers y
configurar todos los clientes
• Cambiar de SGBD requiere reinstalar todos los clientes
• Cambiar el esquema de la BD puede afectar a los clientes
• Cambiar la lógica del negocio implica recompilar y
desplegar en todos los clientes
• Costos de conexión con la BD son altos. Cada cliente una
conexión.
• La red se puede sobrecargar. Cada sentencia SQL usa la
red.
A. Goñi. Dpto. LSI, UPV/EHU
Arquitectura física en 2 niveles:
cliente flaco/servidor gordo
• Parte de la lógica del negocio se
combina con el nivel de datos
CLIENTE
NIVEL DE
PRESENTACIÓN
NIVEL DE
LÓGICA DEL
NEGOCIO 1
SERVIDOR
NIVEL DE
DATOS + LÓGICA
DEL NEGOCIO 2
• Se usan procedimientos almacenados (stored procedures)
en la BD. Un procedimiento almacenado puede servir para
ejecutar una serie de sentencias SQL.
• Comunicación Cliente/Servidor en SQL + Proc. almacenados
• Se necesitan APIs como por ejemplo JDBC y/o ODBC
• Deben instalarse DRIVERS de la BD en todos los clientes
A. Goñi. Dpto. LSI, UPV/EHU
24
25
Arquitectura física en 3 niveles
CLIENTE
CLIENTE
SERVIDOR
CLIENTE
SERVIDOR
Nivel de Presentación
Nivel de Lógica del Negocio
(en SERVIDORES DE
APLICACIONES)
Nivel de Datos
BASE DE
DATOS
A. Goñi. Dpto. LSI, UPV/EHU
26
CLIENTE
public class PedirBillete extends JFrame {
GestorBilletes gestorBilletes;
Presentación
void jButton1_actionPerformed(ActionEvent e) {
int res = gestorBilletes.getBillete(jTextField1.getText()).getNum();
if (res<0) jTextArea1.append("Error al asignar billete");
else jTextArea1.append("Asignado. \nReferencia: "+res+"\n");} }
BD
Datos
SERVIDOR
DATOS
SERVIDOR APLICACIONES
INSTALAR LA
CLASE
sun.jdbc.odbc.
JdbcOdbcDriver
Y DEFINIR
FUENTE
DATOS ODBC
“Billetes”
A. Goñi. Dpto. LSI, UPV/EHU
public class ServidorGestorBilletesBD
Lógica del Negocio
implements GestorBilletes
{ public ServidorGestorBilletesBD() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
public Billete getBillete(String nom)
{ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
int act = sent.executeUpdate("UPDATE BILLETES …“);
if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
27
BD
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
CLIENTE
APLICACIONES
CLIENTE
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
SERVIDOR
CLIENTE
DATOS
APLICACIONES
CLIENTE
CLIENTE
CLIENTE
CLIENTE
SERVIDOR
CLIENTE
APLICACIONES
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE
CLIENTE
¡¡ SÓLO LOS SERVIDORES
CLIENTE
CLIENTE
DE APLICACIONES TIENEN
CLIENTE
CONEXIONES ABIERTAS
CLIENTE
CON LA BD!!
A. Goñi. Dpto. LSI, UPV/EHU
28
Arquitectura física en 3 niveles
• Sólo hay que instalar los drivers de la BD en los
nodos donde se encuentre la lógica del negocio
(nodos servidores)
• Cambiar de SGBD/esquema de la BD NO requiere
reinstalar todos los clientes. Sólo los de la lógica del
negocio.
• Cambiar la lógica del negocio NO implica recompilar y
desplegar en todos los clientes.
• Costos de conexión con la BD NO son tan altos. Los
clientes no realizan conexiones con la BD. Sólo los
servidores con la lógica del negocio lo hacen.
En general, se MEJORA en EFICIENCIA,
MANTENIMIENTO y EXTENSIBILIDAD
A. Goñi. Dpto. LSI, UPV/EHU
Las aplicaciones Web permiten más
niveles
CLIENTE
(Nav. Web)
CLIENTE
(Nav. Web)
SERVIDOR
WEB
SERVIDOR
WEB
SERVIDOR
APLICACIONES
CLIENTE
(Nav. Web)
CLIENTE
(Nav. Web)
SERVIDOR
WEB
SERVIDOR
APLICACIONES
A. Goñi. Dpto. LSI, UPV/EHU
BASE DE
DATOS
Nivel de
Presentación
(ejecución)
Nivel de Presentación
(instalación)
Nivel de Lógica del Negocio
Nivel de Datos
29
30
CLIENTE
Navegador
Web
Ejecutar
Presentación
SERVIDOR
WEB
BD
Datos
HTML + JSP +
Bean
Instalar
Presentación
SERVIDOR
DATOS
SERVIDOR APLICACIONES
INSTALAR LA
CLASE
sun.jdbc.odbc.
JdbcOdbcDriver
Y DEFINIR
FUENTE
DATOS ODBC
“Billetes”
A. Goñi. Dpto. LSI, UPV/EHU
public class ServidorGestorBilletesBD
Lógica del Negocio
implements GestorBilletes
{ public ServidorGestorBilletesBD() {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
public Billete getBillete(String nom)
{ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
int act = sent.executeUpdate("UPDATE BILLETES …“);
if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
BD
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
APLICACIONES
sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
APLICACIONES
SERVIDOR WEB
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
SERVIDOR WEB
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
A. Goñi. Dpto. LSI, UPV/EHU
SERVIDOR
APLICACIONES
SERVIDOR
sun.jdbc.odbc.JdbcOdbcDriver
DATOS
EN LOS CLIENTES NO HAY
QUE INSTALAR NADA
(EXCEPTO NAVEGADOR
WEB+ INTERNET)
31
32
Arquitectura física en 3 niveles
• Existe tecnología que permite construir
aplicaciones siguiendo esta filosofía de
componentes y objetos distribuidos
(server-side components)
– Entreprise JavaBeans (EJBs) es la arquitectura de
componentes para la plataforma Java 2 Enterprise Edition
(J2EE). Definido por Sun Microsystems
• El nivel de presentación se puede dividir más usando Java Applets,
Servlets y/o JSPs
– CORBA es una arquitectura para comunicación entre
objetos distribuidos a través de ORBs (Object Request
Brokers). Es un estándar definido por OMG.
– DCOM/COM+ y la plataforma .NET es la tecnología
equivalente desarrollada por Microsoft
A. Goñi. Dpto. LSI, UPV/EHU
33
Arquitectura física en 3 niveles
• Pero también se puede conseguir con
tecnología “sencilla” de Java:
– Construcción de interfaces gráficas en Java (AWT y
SWING) para definir el NIVEL DE PRESENTACIÓN
– Ejecución del NIVEL DE PRESENTACIÓN EN UN
navegador WEB (Págs. con Applets o Págs. JSPs)
– Computación con objetos distribuidos (RMI) para
definir el NIVEL LÓGICA DEL NEGOCIO e
invocarlo desde el NIVEL DE PRESENTACIÓN
– Llamadas a JSPs y de ellos a JavaBeans
– Conexión con BDs relacionales (JDBC) para
conseguir la comunicación entre NIVEL LÓGICA
DEL NEGOCIO y DATOS
A. Goñi. Dpto. LSI, UPV/EHU
Preguntas: ¿qué cambios habría que
realizar si…?
• Se quisiera cambiar el SGBD de
Access a MySQL
• Si se quisiera cambiar la BD: por
ejemplo tabla BILLETES =>
ENTRADAS
• Quisiéramos una nueva regla del
negocio: no permitir comprar más de 6
entradas a la misma persona
• Se desea que la respuesta salga en
otra ventana
A. Goñi. Dpto. LSI, UPV/EHU
34
35
2. Construcción de
interfaces gráficas en Java
AWT y Swing
A. Goñi. Dpto. LSI, UPV/EHU
36
Í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)
A. Goñi. Dpto. LSI, UPV/EHU
39
AWT. Componentes principales
• Jerarquía de clases de AWT:
COMPONENTE
Applet
CONTENEDOR
(todo contenedor es
un componente)
A. Goñi. Dpto. LSI, UPV/EHU
40
La jerarquía de clases de AWT sigue
un patrón de diseño COMPOSITE
Componente
ComConc1
ComConcN
Clase Contenedor
add (Componente c)
-- el método add añade
-- componentes
-- al contenedor
A. Goñi. Dpto. LSI, UPV/EHU
Contenedor
ContConc1
ContConcM
Un contenedor se compone de varios
componentes, los cuales pueden ser
componentes concretos o pueden ser
contenedores. Estos contenedores pueden estar
a su vez compuestos de varios componentes.
41
La jerarquía de clases de AWT sigue
un patrón de diseño COMPOSITE
COMPONENTE
Applet
Las posibilidades son infinitas…
CONTENEDOR
(todo contenedor es
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
Un diseño de clases como este sería
francamente malo …
Button
*
*
CheckBox
TextField
*
Frame
*
…
- 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
Componentes principales de Swing
Applet
JWindow
JDialog
JApplet
A. Goñi. Dpto. LSI, UPV/EHU
JComponent
JFrame
JPanel JList JComboBox
JMenuBar
JTextField,
JTextArea,
JButton…
44
Contenedores
• El contenedor más importante es el Frame/JFrame, pero
también hay otros como Panel/JPanel y Dialog/JDialog.
• Clases Frame/JFrame
– Ventana lisa a la que se le puede añadir título y ofrece los iconos
para maximizar, minimizar y destruir.
– Es el único contenedor al que se le pueden insertar menús
• Clases Panel/JPanel
– Son los contenedores genéricos que sirven para agrupar
componentes. Es la clase que se utiliza para insertar contenedores
dentro de otros contenedores (subpaneles dentro de paneles)
– La clase JFrame de Swing incluye de manera automática un Panel.
La clase Frame de AWT NO.
A. Goñi. Dpto. LSI, UPV/EHU
45
Para acceder al JPanel
asociado al JFrame
A. Goñi. Dpto. LSI, UPV/EHU
46
jPanel4
jComboBox1
jRadioButton1
jPanel2
jRadioButton2
jPanel3
jTextArea1
jButton1
jPanel1
A. Goñi. Dpto. LSI, UPV/EHU
Componentes principales
de AWT / Swing
47
• Clases TextField / JTextField
– área de entrada de texto de una línea
• Clases TextArea / JTextArea
– permite introducir varias líneas de texto
– también puede usarse para mostrar texto
– TextArea implementa un scroll vertical y
horizontal por cada área de texto
– JTextArea no añade automáticamente un
scroll. Hay que añadir el JTextArea a un
JScrollPane
A. Goñi. Dpto. LSI, UPV/EHU
48
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
Componentes principales
de AWT / Swing
• Clases Button / JButton
– Creación de botones. Un botón nos
permitirá realizar algún tipo de acción
cuando sea pulsado.
• Clases Label / JLabel
– Pueden mostrar información
– Se suelen utilizar junto con los campos de
texto.
A. Goñi. Dpto. LSI, UPV/EHU
49
50
JFrame
A. Goñi. Dpto. LSI, UPV/EHU
Componentes principales
de AWT / Swing
• 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
51
52
A. Goñi. Dpto. LSI, UPV/EHU
Componentes principales
de AWT / Swing
• Clases List / JList
– Las listas desplazables permiten introducir
una serie de opciones que después el
usuario puede elegir. En ocasiones son
utilizadas para evitar la saturación de
componentes en la pantalla.
– El List de AWT incluye un scroll que
aparece cuando los elementos en la lista
no caben en el espacio asignado al List.
– El JList no. Hay que añadirlo a un
JScrollPane.
A. Goñi. Dpto. LSI, UPV/EHU
53
54
Pero sólo si se hace antes de que
se muestre el JFrame
b.elementos.addElement(“C++”);
aquí no funcionaría
Con vector no funciona si la lista es “dinámica”
A. Goñi. Dpto. LSI, UPV/EHU
55
Por ejemplo, javax.Swing ofrece la clase
DefaultListModel, que proporciona los
mismos métodos que Vector
Para listas “dinámicas” usar un ListModel
A. Goñi. Dpto. LSI, UPV/EHU
56
A. Goñi. Dpto. LSI, UPV/EHU
Componentes principales
de AWT / Swing
57
• Clases Choice / JComboBox
– Esta clase se utiliza para crear menús de
opciones.
– Su ventaja es el poco espacio que ocupan
los menus desplegables en pantalla.
A. Goñi. Dpto. LSI, UPV/EHU
58
A. Goñi. Dpto. LSI, UPV/EHU
JTable
JTable para mostrar y
editar tablas de datos
Se puede
redimensionar…
Modificar valores
en celdas…
A. Goñi. Dpto. LSI, UPV/EHU
59
Componentes principales
de AWT / Swing
• Creación de menús en Swing
– La clase JFrame es el único contenedor que
puede alojar a una barra de menús.
– La clase JMenuBar permite crear la barra de
menús sobre la que se insertarán los menús.
– La clase JMenu permite crear menús a los
que se les da un nombre y que muestran
“elementos” en una ventana desplegable
– Los “elementos” del menú pueden ser
objetos de JMenuItem o de JMenu (para
menús en cascada).
• En AWT existen otras clases similares
A. Goñi. Dpto. LSI, UPV/EHU
60
61
Menús en Swing
JMenu
JMenu
JMenuBar
JMenuItem
A. Goñi. Dpto. LSI, UPV/EHU
JMenuItem
62
JDeveloper ayuda un poco…
A. Goñi. Dpto. LSI, UPV/EHU
63
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
A. Goñi. Dpto. LSI, UPV/EHU
65
Administradores de diseño: Layout
• Sirven para decidir dónde se coloca un
componente dentro del contenedor
contenedor.add(componente);
• FlowLayout (administrador por defecto para Panel)
– va añadiendo los componentes en una línea
hasta que se termina y pasa a la siguiente
• BorderLayout (administrador de Frame y Dialog )
– añade los componentes en 5 áreas: norte, sur,
oeste, este y centro
• El administrador por defecto se puede cambiar:
contenedor.setLayout(new BorderLayout());
A. Goñi. Dpto. LSI, UPV/EHU
Administradores de diseño: Layout
• Si se desea colocar el componente en
unas determinadas coordenadas,
entonces hay que quitar el administrador
de diseño
componente.setLayout(null);
// o setLayout(new XYLayout());
• Suponiendo que this es un contenedor y
textField1 un componente suyo
setLayout(null);
textField1.setBounds(15,20,50,60);
lo coloca en: x
A. Goñi. Dpto. LSI, UPV/EHU
y
anchura
altura
66
67
Label
en BorderLayout.NORTH
Panel
con BorderLayout
Panel con GridLayout(4,3) situado en BorderLayout.CENTER
Panel con FlowLayout situado en BorderLayout.SOUTH
A. Goñi. Dpto. LSI, UPV/EHU
68
jPanel1
jPanel2
A. Goñi. Dpto. LSI, UPV/EHU
jPanel4
69
Ventajas al definirlo con
administradores de
diseño: se redibujan los
componentes
automáticamente al
cambiar el tamaño de la
ventana.
A. Goñi. Dpto. LSI, UPV/EHU
70
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…
A. Goñi. Dpto. LSI, UPV/EHU
72
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
Ventana MODAL: hasta
que no se cierre no puede
cambiarse de ventana
modal
a true
A. Goñi. Dpto. LSI, UPV/EHU
74
Necesario asociar el FileDialog a un Frame “padre”,
pero no es necesario llamar a getDirectory/File desde él
A. Goñi. Dpto. LSI, UPV/EHU
75
Gestión de eventos
• Al diseñar una interfaz gráfica hay que
tener en cuenta que se producirán
ciertos EVENTOS como consecuencia
de las acciones del usuario.
• Por lo tanto, el programador tendrá que
preparar una serie de ACCIONES para
procesar los eventos del usuario.
A. Goñi. Dpto. LSI, UPV/EHU
76
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
Los eventos son objetos
Los eventos de bajo nivel son objetos de clases
• ContainerEvent
– se producen cuando se añaden/eliminan componentes
• FocusEvent
– se generan cuando el componente ha ganado o
perdido el enfoque (foco) del teclado
• InputEvent (con subclases KeyEvent y MouseEvent)
– se generan cuando el usuario pulsa una tecla, mueve
el ratón o hace click con él
• WindowEvent
– se generan cuando se usa alguno de los controles de
ventana (minimizar, cerrar, …)
Estas clases son subclases de java.awt.AWTEvent
A. Goñi. Dpto. LSI, UPV/EHU
79
Los eventos son objetos
Los eventos de alto nivel son objetos de clases
• ActionEvent
– se producen cuando se realizan acciones específicas sobre
componentes: ej: pulsaciones de botones
• AdjustmentEvent
– se generan cuando una barra de desplazamiento cambia
• ItemEvent
– se generan cuando el usuario cambia una elección, una lista
o casilla de verificación (Choice,List,CheckBox)
• TextEvent
– se generan cuando cambia el texto en un componente
TextArea o TextField
Estas clases son subclases de java.awt.AWTEvent
A. Goñi. Dpto. LSI, UPV/EHU
80
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);
obj1 contiene una referencia a un
OBJETO GRÁFICO (botón,
ventana, lista desplegable,
checkbox, etc) sobre el que se
quiere definir un
comportamiento ante EVENTOS
En tiempo de
ejecución sucede
un EVENTO
que afecta al
objeto de obj1
A. Goñi. Dpto. LSI, UPV/EHU
obj2 contiene una referencia a un
objeto de una clase que implementa
el interface XXXListener.
public interface XXXListener {
....
void accionYYY (AWTEvent e);
}
Se crea un objeto
evento(AWTEvent)
y se pasa el control
al objeto oyente
(el de obj2)
El objeto oyente ejecutará el
método correspondiente a la
acción (Ej.: accionYYY)
usando el objeto Evento
generado como parámetro
82
Tras pulsar
el botón
OyenteBoton es INNER CLASS (clase definida dentro de otra).
Por eso se puede acceder a los atributos jPanel1, jButton1,…
A. Goñi. Dpto. LSI, UPV/EHU
Asociar componentes gráficos
con Listeners
• A cada componente gráfico tenemos que
decirle qué interfaz Listener queremos
implementar: addXXXListener()
• Por ejemplo:
– addActionListener(ActionListener oyente)
– addItemListener(ItemListener oyente)
• NO ES NECESARIO aprenderse los
distintos tipos de Listeners, si se usa una
herramienta visual de desarrollo.
A. Goñi. Dpto. LSI, UPV/EHU
83
84
1) Hacer click en el componente
2) Seleccionar el
Evento
(actionPerformed)
y hacer click
3) Escribir el
código donde
indica JDeveloper
A. Goñi. Dpto. LSI, UPV/EHU
85
Clases Adapter
• Algunos Listeners tienen varios métodos, pero tal
vez no queramos implementarlos todos (porque no
queremos responder a todos los tipos de eventos
posibles).
• Sin embargo, Java obliga a implementar todos los
métodos de una interfaz
– Conclusión: muchas veces se proporcionarán
implementaciones vacías a los métodos.
• Por eso, Java ofrece al programador unas clases
adaptadoras (Adapter) que implementan todos los
métodos de las interfaces (dejándolos vacíos)
• Usando una herramienta visual NO es problema
A. Goñi. Dpto. LSI, UPV/EHU
JDeveloper genera las clases Oyente como
INNER CLASS sin nombre
Tras pulsar
el botón
A. Goñi. Dpto. LSI, UPV/EHU
86
87
Definición de una clase
SIN NOMBRE que
implementa el interface
ActionListener
button1.addActionListener(new
ESTE CÓDIGO
SE GENERA DE
MANERA
AUTOMÁTICA
CON JDeveloper
java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
button1_actionPerformed(e);
}
});
LA ACCIÓN HAY QUE
PROGRAMARLA, CLARO
void button1_actionPerformed(ActionEvent e) {
textArea1.setText("Opción: "+checkboxGroup1.getCurrent().getLabel());
}
A. Goñi. Dpto. LSI, UPV/EHU
88
A. Goñi. Dpto. LSI, UPV/EHU
89
Se puede usar un único método para tratar los
eventos de los dos JRadioButton. El texto se
puede obtener del objeto EVENTO !!
A. Goñi. Dpto. LSI, UPV/EHU
90
Se puede usar un único método para tratar los
eventos de los dos JRadioButton. El texto se puede
obtener del objeto EVENTO (ActionEvent e)
Para obtener información de contexto del
evento (como la etiqueta del componente
gráfico sobre el que se ha producido el evento)
A. Goñi. Dpto. LSI, UPV/EHU
Cuando entra el ratón en el botón91
Inicialmente…
Punto donde se
encuentra el ratón
Al hacer “drag” dentro del botón
A. Goñi. Dpto. LSI, UPV/EHU
Al salir el ratón del botón
92
A. Goñi. Dpto. LSI, UPV/EHU
93
jTextField1
Cada vez que se escribe un
carácter en la caja de texto, se
añade al área de texto y se borra
de la caja de texto. Cada 25
caracteres se salta de línea en el
área de texto.
A. Goñi. Dpto. LSI, UPV/EHU
jTextArea1
94
Separación entre Nivel de
Presentación y Lógica del Negocio
• Es conveniente separar el nivel de presentación
del de la lógica del negocio
• El nivel de presentación está formado por las
clases de AWT/Swing
• La llamada al nivel lógica del negocio se realizará
en algún método de respuesta a un evento.
• Se puede incluir un atributo que contenga el objeto
con la lógica del negocio (DE TIPO interface
JAVA)
– Podría conseguirse cambiar la lógica del negocio SIN NECESIDAD
DE cambiar el nivel de presentación. Incluso sin RECOMPILAR, e
incluso haciéndolo EN TIEMPO DE EJECUCIÓN (sin relanzar el
objeto de presentación)
A. Goñi. Dpto. LSI, UPV/EHU
95
Interface LogicaNegocio
hacerX(… )
hacerY(… )
usa
Clase Presentacion
logNe: LogicaNegocio
setLogicaNegocio
(l: LogicaNegocio)
En alguno de los métodos de la clase
Presentación (los que responden a eventos)
se usará:
logNe.hacerX(…)
o bien
logNe.hacerY(…)
A. Goñi. Dpto. LSI, UPV/EHU
Interface LogicaNegocio
96
hacerX(… )
hacerY(… )
usa
Clase Presentacion
logNe: LogicaNegocio
clase LogicaNegocioConcreta
setLogicaNegocio
(l: LogicaNegocio)
hacerX(… ) // Implementada
hacerY(… ) // Implementada
PARA CREAR LA INTERFAZ GRÁFICA CON SU LÓGICA DEL NEGOCIO:
Presentacion p = new Presentacion();
p.setLogicaNegocio(new LogicaNegocioConcreta());
p.setVisible(true);
A. Goñi. Dpto. LSI, UPV/EHU
97
Interface LogicaNegocio
Clase Presentacion
usa
logNe: LogicaNegocio
setLogicaNegocio
(l: LogicaNegocio)
hacerX(… )
hacerY(… )
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
A. Goñi. Dpto. LSI, UPV/EHU
99
Sólo falta proporcionar
la clase que implemente
GestorBilletes…
(con o sin nombre)
A. Goñi. Dpto. LSI, UPV/EHU
100
Interface GestorBilletes
Clase PedirBillete
usa
gestorBilletes:
GestorBilletes
setGestorBilletes
(GestorBilletes)
getBillete(String):int
clase GestorBilletesImp
getBillete(String):int
// Implementada
A. Goñi. Dpto. LSI, UPV/EHU
101
3. Conexión con BDs relacionales en
Java
JDBC
A. Goñi. Dpto. LSI, UPV/EHU
102
Í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
A. Goñi. Dpto. LSI, UPV/EHU
103
Introducción
• JDBC (Java Database Connectivity) es un API; un
conjunto de clases y métodos que se encuentran
en el paquete java.sql y que sirven para
– establecer conexiones con bases de datos
– enviar sentencias SQL a dichas BDs
– procesar los resultados
• Los vendedores de SGBD deben escribir
“drivers”o controladores para JDBC, o al menos,
permitir que programas que usan el API JDBC
puedan conectarse con sus BDs.
Hay muchos: http://industry.java.sun.com/products/jdbc/drivers
A. Goñi. Dpto. LSI, UPV/EHU
104
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 JDBCODBC 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
Arquitectura para JDBC: 4 tipos de drivers
Aplicación JAVA
API de JDBC
JDBC Driver Manager
API de JDBC Driver
Driver puente
JDBC-ODBC
Driver ODBC
SGBD
A. Goñi. Dpto. LSI, UPV/EHU
Distintos tipos de Driver JDBC:
Driver JDBC A) Traduce a APIs nativas del
SGBD.
B) Se comunica con aplicación
intermedia en el servidor
que traslada peticiones al
SGBD
SGBD que se trate
C) Se comunica directamente
con el SGBD
106
APLICACIÓN
Connection c;
Cargar Driver SGBD X
Abrir Conexión BD 1
Crear Statement
Enviar Sentencia SQL
BD 1
Enviar/
Recibir
SQL
BD 2
Statement s
SGBD X
A. Goñi. Dpto. LSI, UPV/EHU
107
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
• Una vez que tenemos una conexión
abierta, se pueden lanzar sentencias SQL
desde el programa Java.
• Para ello hay que crear objetos “Statement”
Statement s = c.createStatement();
// c contiene un objeto de Connection
• Las conexiones hay que cerrarlas cuando
no se necesitan (no queremos enviar más
sentencias SQL a la BD) para liberar
recursos
c.close();
A. Goñi. Dpto. LSI, UPV/EHU
110
La interfaz Connection
• Por defecto, toda sentencia SQL enviada
a un Statement termina con un commit si
tiene éxito.
• Si se quiere que varias sentencias SQL
formen una transacción, se puede hacer
así:
c.setAutoCommit(false);
// Enviar las sentencias SQL que forman
// la transacción
Ejecutar c.commit();
o bien c.rollback();
A. Goñi. Dpto. LSI, UPV/EHU
111
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
NOTA: sólo puede haber un ResultSet “abierto” sobre un
objeto “Statement”
CONCLUSIÓN: si queremos trabajar con dos preguntas
SQL a la vez se necesita definir dos statement diferentes
A. Goñi. Dpto. LSI, UPV/EHU
112
Interfaz Statement
• Se puede cerrar un statement, para liberar
recursos:
s.close();
// s contiene un objeto de Statement
• Se puede limitar el número máximo de tuplas que
queremos que nos devuelva el SGBD:
s.setMaxRows(maxTuplas);
• Se puede limitar el número máximo de segundos
que queremos que espere el Driver:
s.setQueryTimeout(maxSegundos);
A. Goñi. Dpto. LSI, UPV/EHU
113
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
A. Goñi. Dpto. LSI, UPV/EHU
115
ResultSet rs = s.executeQuery(“SELECT * FROM BILLETES”);
rs.next()
true
int i = rs.getInt(1);
1
String est = rs.getString(2);
OCUPADO
A. Goñi. Dpto. LSI, UPV/EHU
116
ResultSet rs = s.executeQuery(“SELECT * FROM BILLETES”);
rs.next()
true
int i = rs.getInt(“NUMERO”);
0
String est = rs.getString(“ESTADO”);
OCUPADO
A. Goñi. Dpto. LSI, UPV/EHU
117
ResultSet rs = s.executeQuery(“SELECT * FROM BILLETES”);
rs.next()
true
Object i = rs.getObject(1);
i.toString()
“2”
String est = rs.getString(“ESTADO”);
LIBRE
A. Goñi. Dpto. LSI, UPV/EHU
118
ResultSet rs = s.executeQuery(“SELECT * FROM BILLETES”);
rs.next()
false
A. Goñi. Dpto. LSI, UPV/EHU
119
Usando sentencias con parámetros
• Algunas sentencias SQL se repiten varias
veces cambiando sólo algunos valores.
– Se pueden parametrizar
Sea c un objeto de Connection
PreparedStatement s =
c.prepareStatement(“SELECT NOMBRE FROM
PERSONAS WHERE CIUDAD=? AND EDAD>?”);
s.setString(1,“SS”); // Poner SS en 1er parámetro
s.setInt(2,25); // Poner 25 en 2º parámetro
ResultSet r = s.executeQuery(); // ...
// Se puede reejecutar s.setString(1,“Bi”);..
A. Goñi. Dpto. LSI, UPV/EHU
120
A. Goñi. Dpto. LSI, UPV/EHU
121
A. Goñi. Dpto. LSI, UPV/EHU
122
A. Goñi. Dpto. LSI, UPV/EHU
123
A. Goñi. Dpto. LSI, UPV/EHU
124
1
3
4
Seleccionar una BD
Access previamente
creada
A. Goñi. Dpto. LSI, UPV/EHU
2 Agregar y escoger “MAccess Driver”
125
A. Goñi. Dpto. LSI, UPV/EHU
126
A. Goñi. Dpto. LSI, UPV/EHU
127
EL CÓDIGO ANTERIOR PODRÍA SUSTITUIRSE POR
EL SIGUIENTE, DONDE SE USA UNA LLAMADA A
UNA SENTENCIA SQL PARAMETRIZADA
A. Goñi. Dpto. LSI, UPV/EHU
128
A. Goñi. Dpto. LSI, UPV/EHU
129
Conexión con el nivel de presentación
• La clase ServidorGestorBilletes es una clase
que contiene la LÓGICA DEL NEGOCIO
– inicializarSala y getBillete
• Y que realiza llamadas al NIVEL DE DATOS
– Son todas las sentencias JDBC
• Para realizar la conexión con el NIVEL DE
PRESENTACIÓN, bastará con implementar la
interfaz utilizada por el mismo y asignar un
objeto de la lógica del negocio al objeto de
presentación
A. Goñi. Dpto. LSI, UPV/EHU
130
HAY QUE INDICAR EXPLÍCITAMENTE
QUE SE IMPLEMENTA LA INTERFAZ
CREAR OBJETO LÓGICA DEL NEGOCIO
CREAR OBJETO
DE PRESENTACIÓN
ASIGNAR ESA
LÓGICA DEL NEGOCIO
AL OBJETO PRESENTACIÓN
A. Goñi. Dpto. LSI, UPV/EHU
131
Interface GestorBilletes
Clase PedirBillete
usa
gestorBilletes:
GestorBilletes
setGestorBilletes
(GestorBilletes)
getBillete(String):int
clase ServidorGestorBilletesBD
getBillete(String):int
inicializarSala(int)
crearTablaBilletes()
A. Goñi. Dpto. LSI, UPV/EHU
132
4. Mecanismos de serialización en
Java
A. Goñi. Dpto. LSI, UPV/EHU
133
Serialización de objetos
• Java ofrece unos servicios de serialización
de objetos que CONVIERTEN OBJETOS EN
SERIES DE BYTES
• Son útiles para:
– proporcionar persistencia de objetos, ya que una
vez convertidos los objetos en bytes se pueden
guardar en Streams de bytes (ficheros)
– enviar mensajes entre objetos de distintas
máquinas (se serializan dichos mensajes)
• Usando sockets, RMI (Remote Method Invocation)
A. Goñi. Dpto. LSI, UPV/EHU
134
CLASES
Persona
dni: int
nombre: String
suCoche: Coche
Coche
matricula: String
modelo: String
susProp: Vector
OBJETOS
juan:Persona
17832423
“Juan Pérez”
coche1
elena:Persona
17114452
“Elena Pérez”
coche1
coche1:Coche
3541 CGH
“Citroen C4”
<juan,elena>
Se desea guardar el contenido de los objetos juan y
elena en un fichero, o enviarlo por la red…
A. Goñi. Dpto. LSI, UPV/EHU
Por ejemplo, si se quisiera almacenar los
objetos en el fichero personas.txt…
135
PrintWriter fichero = new PrintWriter (new FileWriter("personas.txt"));
fichero.println(juan.toString());
fichero.println(elena.toString());
public class Persona {
…
public String toString ()
{ return dni+ "/"+nombre+ + "/“
+ suCoche.getMat() + "/"+ suCoche.getModelo();}
}
personas.txt
17832423/Juan Pérez/3541 CGH/Citroen C4
17114452/Elena Pérez/3541 CGH/Citroen C4
… pero hay una pega al almacenar los valores. ¿Cómo se
sabe “3541 CGH/Citroen C4” es el MISMO objeto?
A. Goñi. Dpto. LSI, UPV/EHU
136
Serialización de objetos
• Si se quiere que los objetos de una
clase se puedan serializar, en la
definición de dicha clase hay que
indicar que implementa el interfaz
java.io.Serializable
• Entonces se pueden leer/escribir
objetos en
ObjectInputStream/ObjectOutputStream
con los métodos readObject/writeObject
A. Goñi. Dpto. LSI, UPV/EHU
137
Serialización de objetos
• Para que un determinado atributo de una
clase no se serialice hay que declararlo como
transient
– Por ejemplo un atributo que sea un Stream
• Los métodos writeObject y readObject
funcionan bien con los tipos básicos, Strings,
Arrays, Vector, etc. Pero también se pueden
redefinir para una determinada clase
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException;
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
A. Goñi. Dpto. LSI, UPV/EHU
138
Serialización de objetos
• Al hacer writeObject de un objeto se
serializan todos los objetos contenidos
en él, y así recursivamente.
• Hay que tener en cuenta que NO SE
SERIALIZAN LOS ATRIBUTOS static
A. Goñi. Dpto. LSI, UPV/EHU
Por ejemplo, si se quisiera almacenar los
objetos en el fichero personas.dat…
139
ObjectOutputStream fichero =
new ObjectOutputStream (new FileOutputStream("personas.dat"));
fichero.writeObject(juan);
fichero.writeObject(elena);
public class Persona implements Serializable{
…
}
writeObject escribirá en personas.dat el objeto juan junto
con su objeto incrustado coche1, y después escribirá el
objeto elena con su objeto incrustado coche1 (¡¡el mismo!!)
A. Goñi. Dpto. LSI, UPV/EHU
Por ejemplo, si se quisiera enviar los objetos
por la red …
140
ObjectOutputStream socketComoStream =
new ObjectOutputStream (socket.getOutputStream());
socketComoStream.writeObject(juan);
socketComoStream.writeObject(elena);
public class Persona implements Serializable{
…
}
writeObject enviará por el socket el objeto juan junto con su
objeto incrustado coche1, y después enviará el objeto elena
con su objeto incrustado coche1 (¡¡el mismo!!)
A. Goñi. Dpto. LSI, UPV/EHU
141
Ejemplo de serialización de un vector
• Dado un vector:
Vector billetes;
• Se puede escribir en el fichero
billetes.dat
ObjectOutputStream sal =
new ObjectOutputStream(new
FileOutputStream(“billetes.dat”));
sal.writeObject(billetes);
• Y se puede leer del fichero billetes.dat
ObjectInputStream ent =
new ObjectInputStream(new
FileInputStream(“billetes.dat”));
billetes=(Vector)ent.readObject();
A. Goñi. Dpto. LSI, UPV/EHU
142
Nueva lógica del negocio para
el ejemplo de PEDIR
BILLETES utilizando
MECANISMOS DE
SERIALIZACIÓN para la
persistencia
A. Goñi. Dpto. LSI, UPV/EHU
143
Interface GestorBilletes
Clase PedirBillete
usa
gestorBilletes:
GestorBilletes
setGestorBilletes
(GestorBilletes)
getBillete(String):int
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.
A. Goñi. Dpto. LSI, UPV/EHU
El servidor está a la espera de 145
peticiones de clientes. Recoge los
parámetros y devuelve el resultado por
medio de SOCKETS. Utiliza la clase
ServidorGestorBilletesBD
A. Goñi. Dpto. LSI, UPV/EHU
146
Interface GestorBilletes
Clase PedirBillete
usa
gestorBilletes:
GestorBilletes
getBillete(String):int
setGestorBilletes
(GestorBilletes)
clase GestorBilletesCliente
getBillete(String):int
En distintos ordenadores
socket
clase ServidorGestorBilletesBD
getBillete(String):int
inicializarSala(int)
crearTablaBilletes()
A. Goñi. Dpto. LSI, UPV/EHU
usa
clase Servidor
147
5. Introducción a la
computación distribuida con
Java RMI
A. Goñi. Dpto. LSI, UPV/EHU
Índice
•
•
•
•
•
Introducción a RMI
Interfaz remota
Servidor remoto
Cliente
Arquitectura RMI: stubs, skeletons,
rmiregistry, serialización de
parámetros/resultados, política de
seguridad
• Ejemplo
• Conexión entre nivel de presentación,
lógica del negocio y nivel de datos
A. Goñi. Dpto. LSI, UPV/EHU
148
149
Introducción a RMI
• RMI (Remote Method Invocation) es un API; un
conjunto de clases y métodos que se encuentran
en el paquete (java.rmi)y que sirven para
– desarrollar aplicaciones distribuidas en Java
– que tengan la misma sintaxis y semántica que
aplicaciones no distribuidas
• Equivalente a RPC (Remote Procedure Call)
• Existen otros estándares como CORBA
– Más extenso ya que sirve para poder llamar a servicios
construidos con distintos lenguajes de programación (y
no sólo Java)
A. Goñi. Dpto. LSI, UPV/EHU
150
Introducción a RMI
Clase Cliente1
....
Clase ClienteN
....
EN NODOS CLIENTE
Clase GestorBilletes
- listaBilletes: Vector
- maxBilletes: int
+ getGestor(): GestorBilletes
+ getBillete(nom: String): int
// Dev. nº billete asignado o -1 si no hay
-- Clase con 1 sola instancia (Singleton)
-- El método static getGestor() la devuelve
EN EL NODO SERVIDOR
No es posible realizar lo siguiente en una clase cliente:
GestorBilletes g = GestorBilletes.getGestor();
return g.getBillete("Kepa Sola");
Es un objeto de una máquina virtual Java remota
A. Goñi. Dpto. LSI, UPV/EHU
151
Introducción a RMI
• Para construir una aplicación
Cliente/Servidor donde un cliente acceda a
un servicio remoto (clase remota) usando
RMI hay que:
• 1.- Definir una interfaz remota
• 2.- Implementar dicha interfaz remota
(construir el servidor RMI)
• 3.- Implementar el cliente RMI que accede
al servicio remoto
A. Goñi. Dpto. LSI, UPV/EHU
152
Interfaz remota
Interfaz GestorBilletes
Cliente1
....
+ getBillete(nom: String): int
ClienteN
....
// Dev. nº billete asignado o -1 si no hay
-- INTERFAZ REMOTA
RMI permite que se llamen a objetos remotos.
Para ello, hay que definir una interfaz REMOTA.
Así, en un cliente podría ejecutarse lo siguiente:
GestorBilletes g;
// Código para obtener la dirección del objeto
// remoto y dejarlo en g
return g.getBillete(“Kepa Sola”);
A. Goñi. Dpto. LSI, UPV/EHU
153
Interfaz Remota
// GestorBilletes.java
import java.rmi.*;
public interface GestorBilletes
extends Remote
{
public int getBillete(String nom)
throws RemoteException;
}
GestorBilletes.java
realiza
Interfaz java.rmi.Remote
-- INTERFAZ REMOTA
Interfaz GestorBilletes
+ getBillete(nom: String): int
-- INTERFAZ REMOTA
HAY QUE TENER EN CUENTA QUE:
• La interfaz remota debe extender java.rmi.Remote
• Y todos los métodos definidos en él deben declararse como que
pueden lanzar la excepción java.rmi.RemoteException
A. Goñi. Dpto. LSI, UPV/EHU
154
Servidor Remoto
Clase java.rmi.server.UnicastRemoteObject
-- CLASE REMOTA
Interfaz java.rmi.Remote
-- INTERFAZ REMOTA
extiende
extiende
Clase ServidorGestorBilletes implementa
+ getBillete(nom: String): int
Interfaz GestorBilletes
+ getBillete(nom: String): int
-- CLASE REMOTA
-- INTERFAZ REMOTA
La clase servidor remoto:
• implementa los métodos de la interfaz remota
• extiende java.rmi.server.UnicastRemoteObject
La clase servidor remoto creará un objeto de sí misma y
lo registrará con un nombre (para que objetos de clases
clientes accedan a él y ejecuten sus métodos remotamente).
A. Goñi. Dpto. LSI, UPV/EHU
Servidor Remoto
155
// ServidorGestorBilletes.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
public class ServidorGestorBilletes
extends UnicastRemoteObject
implements GestorBilletes
{
private Vector listaBilletes = new Vector();
private static int maxBills = 50;
public ServidorGestorBilletes()
throws RemoteException{}
public int getBillete(String nom)
throws RemoteException {
int num = listaBilletes.size()+1;
if (num>maxBills) return -1;
listaBilletes.addElement(nom);
System.out.println("Asignado billete a: "+nom);
return num; }
public static void main(String[] args) {...} }
A. Goñi. Dpto. LSI, UPV/EHU
156
Servidor Remoto
// Método main de ServidorGestorBilletes.java
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
try {
ServidorGestorBilletes objetoServidor =
new ServidorGestorBilletes();
String servicio = "//localhost/gestorBilletes";
//
"//localhost:NumPuerto/NombreServicio"
// Registrar el servicio remoto
Naming.rebind(servicio,objetoServidor);
} catch (Exception e)
{System.out.println("Error al lanzar el servidor");}
}
A. Goñi. Dpto. LSI, UPV/EHU
157
Cliente
Clase java.rmi.server.UnicastRemoteObject
-- CLASE REMOTA
extiende
Interfaz java.rmi.Remote
-- INTERFAZ REMOTA
extiende
Clase ServidorGestorBilletes implementa
+ getBillete(nom: String): int
+ getBillete(nom: String): int
-- CLASE REMOTA
-- INTERFAZ REMOTA
La clase cliente:
• busca el objeto remoto que le proporciona
el servicio que le interesa. Para ello debe
conocer el nombre del servicio, pero no la
clase remota (no hace new)
• pide a dicho objeto que ejecute un método
remoto (definido en la interfaz remota)
A. Goñi. Dpto. LSI, UPV/EHU
Interfaz GestorBilletes
usa
Clase Cliente
ges : GestorBilletes
-- CLASE CLIENTE
158
Cliente
Cliente.java
//
import java.rmi.*;
public class Cliente
{
public static void main(String[] args) {
System.setSecurityManager(new RMISecurityManager());
GestorBilletes objRemoto;
String nomServ = "rmi://localhost/gestorBilletes";
//
"rmi://DireccionIP:NumPuerto/NombreServicio"
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
Los clientes RMI siguen un patrón de
diseño INTERFACE
Clase Cliente
Interfaz InterfazRemota
usa
Permite que la clase cliente ejecute métodos de
instancias de otras clases, independientemente de las
mismas (sin siquiera saber cómo se llaman).
Incluso pueden ser clases que todavía no estén
implementadas en el momento de escribir el código de
la clase Cliente.
A. Goñi. Dpto. LSI, UPV/EHU
160
Arquitectura RMI
objRemoto.getBillete("Koldo")
RETURN:
objRemoto
@ObjLocalX
5
Máquina virtual java CLIENTE
Máquina virtual java SERVIDOR
objServidor.getBillete("Koldo")
objServidor
@ObjLocalY
1) Hay que conectar el objeto remoto (objRemoto) con el objeto
servidor (objServidor) para que las llamadas a métodos del primero
sean ejecutadas por el segundo
2) Hay que pasar los valores de los parámetros de los métodos del
cliente al servidor
3) Hay que pasar los resultados de los métodos del servidor al cliente
A. Goñi. Dpto. LSI, UPV/EHU
161
Arquitectura RMI
Programa Cliente
call
return
Programa Servidor
call
return
Skeleton
Stub
Nivel de
Referencia Remota
Nivel de
Referencia Remota
Nivel de
Transporte
Nivel de
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
@ObjStubX
Objeto STUB de la clase
ServidorGestorBilletes_Stub
Máquina virtual java CLIENTE
getBillete
"Koldo"
RETURN:
5
Máquina virtual java SERVIDOR
Objeto SKELETON de la clase
ServidorGestorBilletes_Skeleton
@ObjSkelY
objServidor
@ObjServY
objServidor.getBillete("Koldo")
A. Goñi. Dpto. LSI, UPV/EHU
Objeto de la clase
ServidorGestorBilletes
163
rmic: Generación de stubs y skeletons
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...)
rmic es una herramienta que genera de manera
automática las clases STUB y
SKELETON a partir de la clase remota
(ServidorGestorClientes.class)
A. Goñi. Dpto. LSI, UPV/EHU
164
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
Máquina virtual java situada en IPServidor
puerto 1099
RMIREGISTRY
gestorBilletes @ObjServidor
ServidorGestorBilletes_Stub
....
....
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
• También se puede lanzar desde una aplicación
Java (en el servidor RMI)
java.rmi.registry.LocateRegistry.createRegistry(p)
Crea el proceso rmiregistry en el puerto p.
El rmiregistry lanzado no acaba aunque acabe el servidor RMI
Lanza una excepción si el puerto está ocupado
try { java.rmi.registry.LocateRegistry.createRegistry(1099);
} catch (Exception e)
{System.out.println(“Rmiregistry ya lanzado“+e.toString());}
Código que lanza el rmiregistry y controla la excepción que
se puede levantar al reejecutar varias veces el servidor RMI
A. Goñi. Dpto. LSI, UPV/EHU
167
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
A. Goñi. Dpto. LSI, UPV/EHU
168
RMIREGISTRY y ServidorGestorBilletesBD en la misma
máquina (IPServidor), pero cada uno en DISTINTAS
MÁQUINAS VIRTUALES JAVA
mainServidorGestorBilletesBD
objRemoto:ServidorGestorBillet
esBD
new
RmiRegistry está escuchando en un puerto (1099)
Mirar métodos de LocateRegistry.createRegistry
exportObject(PuertoAnonimo)
Naming
stub: ServidorGestorBilletesBD
_Stub
Rmiregistry
rebind("localhost:1099/gestorBilletes",objRemoto)
getRef()
new(referenciaAObjRemoto)
referenciaAObjRemoto
: PedirBillete
Naming
SOCKET("localhost",1099,"gestorBilletes",stub)
lookup("rmi://IpServidor:1099/gestorBilletes")
SOCKET("IPservidor",1099,"gestorBilletes")
SOCKET(stub)
Se pasa el objeto STUB serializado.
El cliente cargará dinámicamente la clase
ServidorGestorBilletesBD_Stub
stub
stub: ServidorGestorBilletesBD
_Stub
getBillete("Pepe")
SOCKET("IPServidor",PuertoAnonimo,"gestorBilletes","getBillete","Pepe")
numBilleteParaPepe
PresentacionRemoto en otra máquina
A. Goñi. Dpto. LSI, UPV/EHU
SOCKET(numBilleteParaPepe)
169
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
Nombre de fichero (por ejemplo)
Contenido del fichero java.policy:
grant {
permission java.security.AllPermission;
};
NOTA: ESTO NO ES NECESARIO PARA VERSIONES ANTERIORES AL JDK1.2
A. Goñi. Dpto. LSI, UPV/EHU
171
Para no tener que copiar el
STUB en el cliente...
• Al lanzar el CLIENTE hay que dar una
URL para que el Naming.lookup acceda al
stub allí
java -Djava.rmi.server.codebase=http://...
-Djava.security.policy=...
cliente
NOTA: la URL debe acabar con /
http://www.ehu.es
INCORRECTO
http://www.ehu.es/
CORRECTO
A. Goñi. Dpto. LSI, UPV/EHU
Servidor Remoto accede a BD
172
// ServidorGestorBilletes.java
import java.rmi.*;
import java.sql.*;
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
Servidor Remoto accede a BD
173
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
}
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();
String maquina = "//localhost/";
String servicio = "gestorBilletes";
String servicioRemoto = maquina+servicio;
// Registrar el servicio remoto
Naming.rebind(servicioRemoto,objetoServidor);
}catch (Exception e)
{System.out.println("Error: "+e.toString());}
}
}
A. Goñi. Dpto. LSI, UPV/EHU
174
175
Conexión entre nivel de presentación,
lógica del negocio y datos
• Hasta ahora hemos considerado que en el
nivel de presentación, el objeto con la lógica
del negocio se encuentra en un atributo (de
tipo interface Java)
• Utilizando RMI se puede seguir con esa misma
idea, pero en este caso la interfaz es remota
• En vez de asignarle al objeto de presentación,
el objeto con la lógica del negocio se puede
hacer que sea el objeto de presentación quien
lo busque (usando lookup).
• Cambiar la lógica del negocio consiste en
sustituir un objeto por otro en el servidor.
A. Goñi. Dpto. LSI, UPV/EHU
ARQUITECTURA FÍSICA
EN 2 NIVELES:
CLIENTE GORDO / SERVIDOR FLACO
Clase Presentacion
Interface LogicaNegocio
hacerX(… )
hacerY(… )
usa
logNe: LogicaNegocio
setLogicaNegocio
(l: LogicaNegocio)
// Permite cambiar lógica
// negocio en tº ejecuc.
-- En esta clase se llama
-- a la lógica del negocio:
Por ej.: logNe.hacerX(…)
clase LogicaNegocioConcreta
hacerX(…) // Implementaciones
hacerY(…) // llaman al nivel de
// datos (usan JDBC)
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
176
ARQUITECTURA FÍSICA Interface LogicaNegocio
EN 3 NIVELES
hacerX(… )
usando RMI
hacerY(… )
Clase Presentacion
usa
interfaz Remota
logNe: LogicaNegocio
setLogicaNegocio
(String nombreServicio)
// Por ejemplo aquí se
// puede asignar a logNe
-- En esta clase se llama
-- a la lógica del negocio:
Por ej.: logNe.hacerX(…)
-- Para asignar la lógica
-- del negocio se usa
Naming.lookup y NomSer
A. Goñi. Dpto. LSI, UPV/EHU
clase LogicaNegocioConcreta
hacerX(…) // Implementaciones
hacerY(…) // llaman al nivel de
// datos (usan JDBC)
-- La lógica del negocio se crea
-- y se exporta usando:
Naming.rebind y dando un
nombre de servicio: NomSer
177
178
6. Tecnología Java para
construcción de aplicaciones Web
Una introducción a Applets y Java
Server Pages (JSP)
A. Goñi. Dpto. LSI, UPV/EHU
179
Í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
• Aplicación Web: es una aplicación que se
ejecuta en un navegador Web
– Se pueden separar los 3 niveles: presentación,
lógica del negocio y datos
– El nivel de presentación se ejecuta en el cliente
pero se “despliega” en el servidor
– Que haya que cambiar el nivel de presentación no
implica reinstalar todos los clientes
– Se puede añadir parte de la lógica del negocio a
la presentación por motivos de eficiencia:
• Se reducirían llamadas a la lógica del negocio
• Si hubiera que cambiar la lógica del negocio no
implicaría reinstalar todos los clientes
A. Goñi. Dpto. LSI, UPV/EHU
181
Introducción
• La tecnología Java incluye la posibilidad de
crear aplicaciones Web utilizando Applets y
Java Server Pages (JSPs)
• Son dos filosofías distintas:
– Usando applets se descargan aplicaciones desde
el servidor a los clientes.
• En los clientes se ejecutan dichas aplicaciones.
– Con JSPs, en el servidor se ejecutan aplicaciones
que generan código HTML de manera dinámica,
el cual se envía a los clientes
• En los clientes se visualiza el resultado HTML.
A. Goñi. Dpto. LSI, UPV/EHU
182
Applets
Programas Java que se ejecutan en un navegador Web.
Son una herramienta poderosa que soporta la
programación en el lado del cliente, muy importante
en la Web.
Cliente
Navegador
Applet
A. Goñi. Dpto. LSI, UPV/EHU
183
Applets: Restricciones y Ventajas
• (-) Un applet no puede acceder al disco local
• Restringir lectura para que no pueda transmitirse información
local por internet
• Restringir la escritura para que no se puedan escribir virus en
el disco local
• (-) No se puede hacer una conexión de red a otro
nodo de Internet que no sea aquél de donde se ha
descargado
• Existe la posibilidad de firmar digitalmente applets para
eliminar algunas restricciones
• (-) Ejecución más lenta ya que hay que descargarlos
primero
• Mejor comprimir todos los applets en ficheros JAR
• (+) No hay que instalarlos en el cliente. Los applets
son independientes de la plataforma.
• (+) No hay que preocuparse por problemas de
seguridad
A. Goñi. Dpto. LSI, UPV/EHU
184
Métodos de los applets
• Para escribir un applet, hay que heredar de la clase
Applet/JApplet e implementar unos métodos
• init( ):
– Se ejecuta automáticamente cuando se inicializa el applet.
Hay que proporcionar una implementación obligatoriamente
• start( ):
– Se ejecuta cada vez que el applet se hace visible, como
resultado de alguna acción en el navegador.Se llama
siempre después de init()
• stop( ):
– Se ejecuta cada vez que el applet deja de verse
• destroy( ):
– Se ejecuta cuando el applet se descarga definitivamente
(implementarlo si hubiera que liberar recursos)
• No hay por qué implementar el método main()
A. Goñi. Dpto. LSI, UPV/EHU
185
Ejecución de applets
• Para ejecutar un applet:
– Se incrusta en una página Web usando una etiqueta (tag)
– Se visualiza en un navegador que contenga la máquina
virtual java apropiada.
• Las etiquetas apropiadas son:
– Para applets de AWT (Applet), se usa el tag “applet”
• <applet code=“applet” width=100 height=50>
</applet>
– Para applets Swing (JApplet), depende del navegador
• Con Internet Explorer se necesita cargar un
mecanismo de extensión que es un control ActiveX
• Con Netscape hay que cargar el plug-in apropiado
• Como el programador no sabe con qué navegador se
cargará la página, hay que proporcionar las etiquetas
(tags) para ambos
• La herramienta Appletviewer visualiza applets (de
AWT y Swing) incrustados con el tag Applet
A. Goñi. Dpto. LSI, UPV/EHU
186
Ejecución de applets
<html><head><title>Applet1</title></head><hr>
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93“ width="100"
height="50" align="baseline" codebase="http://java.sun.com/products/plugin/1.2.2/jinstall1_2_2-win.cab#Version=1,2,2,0">
<PARAM NAME="code" VALUE="Applet1.class">
<PARAM NAME="codebase" VALUE=".">
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.2.2">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.2.2"
width="200" height="200" align="baseline“ code="Applet1.class" codebase="."
pluginspage="http://java.sun.com/products/plugin/1.2/plugin-install.html">
<NOEMBED>
</COMMENT>
No hay soporte para los applets
</NOEMBED>
</EMBED>
</OBJECT>
<hr></body></html>
A. Goñi. Dpto. LSI, UPV/EHU
Nivel de presentación usando
Applets
• En un Applet/JApplet se pueden incluir
todos los elementos gráficos de los
paquetes AWT y SWING de Java
• En un Applet se puede dibujar, cargar
imágenes y escuchar sonidos
A. Goñi. Dpto. LSI, UPV/EHU
187
188
Nivel lógica del negocio con Applets
• Para obtener la lógica del negocio desde un
applet, se puede usar RMI: la conexión sólo
puede hacerse con el servidor Web
public void init() // Método inicialización del Applet
{try {…
String maquina = this.getCodeBase().getHost();
gestorBilletes =
(GestorBilletes)Naming.lookup("rmi://"+maquina+":“
+numPuerto+servicio);
}
catch(Exception e)
{
// Error al cargar la lógica del negocio
}
LA LÓGICA DEL NEGOCIO SE IMPLEMENTARÍA IGUAL
A. Goñi. Dpto. LSI, UPV/EHU
189
Nivel lógica del negocio con Applets
• Para llamar a la lógica del negocio, se
usa el objeto de gestorBilletes
void jButton1_actionPerformed(ActionEvent e)
{try {
String nombre = jTextField1.getText();
int res = gestorBilletes.getBillete(nombre);
if (res>0)
jTextArea1.append("Asignado. \nReferencia: "+res+"\n");
else if (res==-1)
jTextArea1.append("No hay billetes libres\n");
else if (res==-2)
jTextArea1.append("Error: Inténtelo de nuevo.\n");
}
catch (Exception ex)
{jTextArea1.append("Error: "+ex.toString()+"\n");}
}
A. Goñi. Dpto. LSI, UPV/EHU
190
Se puede validar la entrada en el nivel
de presentación
• Más eficiente: sólo se llama a la lógica
del negocio con entradas correctas
void jButton1_actionPerformed(ActionEvent e)
{try {
String nombre = jTextField1.getText();
if ((nombre.length()<5) || (existeNoLetra(nombre)))
jTextArea1.append("Error: por lo menos 5 letras\n");
else { int res = gestorBilletes.getBillete(nombre);
if (res>0) ...}}
// CÓDIGO ANTERIOR QUE LLAMA
catch (Exception ex) {...}
// A LA LÓGICA DEL NEGOCIO
static boolean existeNoLetra(String s) {
for (int i=0;i<s.length();i++) {
char c = s.charAt(i);
if (!((c >= 'a') && (c <= 'z')
|| (c >= 'A') && (c <= 'Z'))) // Añadir á,é,..ñ,Ñ !!
return true;}
return false;}
A. Goñi. Dpto. LSI, UPV/EHU
191
Ejemplo del applet PedirBilleteAp
Usando Appletviewer
A. Goñi. Dpto. LSI, UPV/EHU
Usando un navegador
¿Validar la entrada es nivel de
presentación o lógica del negocio?
192
• 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
Aplicaciones Java, que devuelven como
resultado HTML.
Normalmente se utilizan para la generación
de páginas dinámicas o control
Servidor
Html
Servlet
A. Goñi. Dpto. LSI, UPV/EHU
194
Plantilla de un Servlet Simple
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>");}}
A. Goñi. Dpto. LSI, UPV/EHU
196
Java Server Pages (JSP)
Páginas HTML con código Java embebido.
En la primera invocación a un JSP el
sistema lo transforma en un Servlet
Servidor
JSP
Html
<HTML>
%%Java
</HTML>
A. Goñi. Dpto. LSI, UPV/EHU
197
Scriptlet JSP
• <% código java %>
– Código Java insertado en una página JSP. Se
procesa en el momento de solicitarla
– Se pueden usar 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++)
out.println("<H2> Hola número "+i+"</H2><BR>");
%>
<P>
<H1> Adiós </H1>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
out: objeto con la
salida HTML
198
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>
A. Goñi. Dpto. LSI, UPV/EHU
199
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>
A. Goñi. Dpto. LSI, UPV/EHU
201
Declaración JSP
• <%! código %>
– El código se ejecuta sólo la primera vez que se
carga la página.
– Puede servir para definir e inicializar variables que
queremos “perduren”
<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>
A. Goñi. Dpto. LSI, UPV/EHU
202
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
Directiva JSP page
• <%@ page atributo="valor" %>
• Órdenes al motor de servlets sobre
configuración
– import =“nombre de clase"
• Si se usan clases que hay que importar
– contentType="MIME-Type"
• Por defecto text/html
• Podría ser text/vnd.wap.wml (para WAP)
– errorPage=“URL"
• Se establece una URL a mostrar si ocurre error en el JSP
– isErrorPage="true|false"
• Si es una página que muestra un error (aparecerá como
URL en la directiva errorPage de alguna página JSP)
• Puede usarse la variable “exception” (objeto con la excep.)
A. Goñi. Dpto. LSI, UPV/EHU
204
Comentarios JSP
• <%-- comentario JSP --%>
• El comentario es ignorado por el traductor de la
página JSP al servlet
– Es un comentario sólo visible en la página JSP
• Si se desea tener un comentario que sea visible
en la página HTML entonces hay que usar
<!– comentario HTML -->
– Visible sólo en el código fuente HTML, no en el
navegador que visualiza dicho código
– NOTA: Los scriptlets JSP, directivas JSP y acciones
JSP dentro de un comentario HTML SÍ SE EJECUTAN
• Se podría enviar un comentario generado de manera dinámica
A. Goñi. Dpto. LSI, UPV/EHU
205
Nivel de presentación con JSPs
• El nivel de presentación sirve para
interactuar con el usuario
• Obtener entrada del usuario
– Utilización de formularios
• Mostrar una salida, resultados,… al
usuario
– Se puede utilizar toda la potencia del
HTML y mostrar: textos, gráficos,
sonidos, vídeo, etc.
A. Goñi. Dpto. LSI, UPV/EHU
206
Entrada de datos: Formularios HTML
A. Goñi. Dpto. LSI, UPV/EHU
207
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN">
<HTML>
<HEAD><TITLE> Formulario </TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2 ALIGN="CENTER">Pantalla de introducción de datos </H2>
<FORM ACTION="http://localhost:8080/alfredo/verDatos.jsp">
<CENTER>
Nombre:
<INPUT TYPE="TEXT" NAME="nombre" VALUE="Filemón"><BR>
Apellido:
<INPUT TYPE="TEXT" NAME="apellido" VALUE="Pi"><P>
<INPUT TYPE="CHECKBOX" NAME="publicidad" CHECKED>Estoy
interesado en recibir publicidad<BR>
<INPUT TYPE="CHECKBOX" NAME="futbol">Me gusta el fútbol<P>
Sexo: <BR>
<INPUT TYPE="RADIO" NAME="sexo" VALUE="hombre"> Hombre <BR>
<INPUT TYPE="RADIO" NAME="sexo" VALUE="mujer"> Mujer <P>
A. Goñi. Dpto. LSI, UPV/EHU
208
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
Entrada de datos: formularios
A. Goñi. Dpto. LSI, UPV/EHU
Recoger datos de formularios
<html><body>
<H1> Estos son los datos recogidos: </H1>
<%
String nombre = request.getParameter("nombre");
String apellido = request.getParameter("apellido");
out.println("Nombre es: "+nombre+" "+apellido);
String sexo = request.getParameter("sexo");
String futbol = request.getParameter("futbol");
String publicidad = request.getParameter("publicidad");
String vida = request.getParameter("vida");
String aficion = request.getParameter("aficion");
out.println("<BR>Sexo: "+sexo);
out.println("<BR>Publicidad: "+publicidad);
out.println(" Fútbol: "+futbol);
out.println(" Afición preferida: "+aficion);
out.println("<BR>Vida:<BR>"+vida); %>
</body></html>
request.
getParameter
("PARAM")
A. Goñi. Dpto. LSI, UPV/EHU
210
<%-- 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();
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> <!-- 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>
A. Goñi. Dpto. LSI, UPV/EHU
</body></html>
MOSTRAR
LA SALIDA
CON HTML
<%-- 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>
A. Goñi. Dpto. LSI, UPV/EHU
</body></html>
<%-- 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>
A. Goñi. Dpto. LSI, UPV/EHU
</body></html>
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
Validar la entrada en la presentación
JavaScript es un lenguaje de programación interpretado que
puede ser ejecutado en un navegador
è PERMITE EJECUCIÓN DE CÓDIGO EN EL CLIENTE
A. Goñi. Dpto. LSI, UPV/EHU
216
Nivel Lógica del Negocio con JSPs
• El nivel de presentación debe limitarse a obtener
la entrada del usuario y a devolver resultados
– Cómo se obtienen los resultados a partir de la entrada lo
deciden/calculan las operaciones propias de la lógica del
negocio.
• Es mejor que el nivel de presentación lo diseñen
“expertos” (diseñadores gráficos)
– Ofrecerles la posibilidad de llamar a la lógica del negocio, a ser
posible sin que conozcan detalles del lenguaje de programación
• Es interesante una arquitectura en varios niveles
• Utilizando la tecnología de JSPs, se puede
llamar a JavaBeans, que implementen la lógica
del negocio
A. Goñi. Dpto. LSI, UPV/EHU
217
Java Beans
• Un Java Bean es una clase Java que:
– Proporciona un constructor sin parámetros
• Explícitamente u omitiendo todos los constructores
– Define todos sus atributos como “private”
– Proporciona métodos accesores “get” y
modificadores “set” a los atributos
•
•
•
•
A. Goñi. Dpto. LSI, UPV/EHU
Si el atributo se llama “nomAtributo”
Entonces el método get será “getNomAtributo()”
Y el set: “setNomAtributo(TipoAtributo t)”
Si el atributo es una propiedad booleana se usará
“isNomAtributo()” en vez de “getNomAtributo()”
218
Instanciar JavaBeans
• Acción JSP: <jsp:useBean atributo=valor * />
• Para encontrar (o crear si no existe) una
instancia de una clase Java Bean
• Posibles atributos:
– id="nombre de la instancia“
– scope="page|request|session|application“
– class=“nombre de la clase Java Bean“
<jsp:useBean id="gestorBilletes"
class="beans.GestorBilletesBean"
scope="request" />
Crea o encuentra la instancia de la clase beans.GestorBilletesBean, accesible
durante la petición actual, y la que podrá referirse con el identificador gestorBilletes
A. Goñi. Dpto. LSI, UPV/EHU
219
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
A. Goñi. Dpto. LSI, UPV/EHU
220
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
Llamar a Java Beans: setProperty
• <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
Llamar a Java Beans: getProperty
<jsp:getProperty name=“identificador del bean“
property=“nombre del atributo"/>
– Para obtener valores de atributos del bean
<jsp:getProperty name="gestorBilletes"
property="nombre" />
Equivalente a:
<%= gestorBilletes.getNombre();%>
NOTA: jsp:setProperty y jsp:getProperty posibilitan llamar a la
lógica del negocio sin usar java: sólo lenguaje de etiquetas
A. Goñi. Dpto. LSI, UPV/EHU
223
<%@ page contentType="text/html;charset=windows-1252"%>
<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"><P>
<INPUT TYPE="submit" value="Pedir Billete">
<INPUT type="reset" VALUE="Borrar Datos">
</FORM></BODY></HTML>
A. Goñi. Dpto. LSI, UPV/EHU
224
<%@ page contentType="text/html;charset=windows-1252"
import="java.util.*"%>
<jsp:useBean id="gestorBilletes" class="beans.GestorBilletesBean"
scope="request" />
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252
<TITLE></TITLE>
</HEAD><BODY>
<H2>PEDIR BILLETE</H2><P>
<%
String nombre = request.getParameter("nombre");
int res = gestorBilletes.getBillete(nombre);
if (res>0)
out.println("<H1> Asignado. </H1> <P> </H2> Referencia: "+res+"</H2>");
else if (res==-1)
out.println("<H1> No hay billetes libres</H1>");
else if (res==-2)
out.println("<H1> Error: Inténtelo de nuevo.</H1>");
%>
</P></BODY></HTML>
A. Goñi. Dpto. LSI, UPV/EHU
225
A. Goñi. Dpto. LSI, UPV/EHU
226
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
Otra posibilidad: añadir otro nivel en
la propia lógica del negocio
Permite separar el servidor Web del servidor de aplicaciones. Así
podría ser compartido por varios servidores Web.
También se puede ver como una manera de reutilizar lógica del
negocio (suponiendo que ya estaba el ServidorGestorBilletesBD)
A. Goñi. Dpto. LSI, UPV/EHU
227
228
Más información…
• Sobre Servlets y JSPs hay mucho más
– Más directivas y acciones
– Librerías de etiquetas existentes
– Posibilidad de crear etiquetas propias
– Trabajo con Servlets (definir sesiones,
usar cookies, etc.), Applets, XML,…
• Bibliografía:
– Core Servlets and Java Server Pages
• Libro en PDF gratuito en:
http://www.coreservlets.com
A. Goñi. Dpto. LSI, UPV/EHU
229
7. Introducción a los Servicios
Web
A. Goñi. Dpto. LSI, UPV/EHU
230
Índice
•
•
•
•
•
•
•
Introducción
HTTP en 5 minutos
XML en 5 minutos
SOAP
WSDL
Usar Servicios Web en JDeveloper
Otros temas
A. Goñi. Dpto. LSI, UPV/EHU
231
Introducción: qué es un Servicio Web
• Definición dada por el W3C
– A Web service is a software system designed to support
interoperable machine-to-machine interaction over a network. It has
an interface described in a machine-processable format
(specifically WSDL). Other systems interact with the Web service in
a manner prescribed by its description using SOAP-messages,
typically conveyed using HTTP with an XML serialization in
conjunction with other Web-related standards
• 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
Introducción: Ventajas de los SW
NO HAY RESTRICCIÓN
SOBRE LENGUAJES,
PLATAFORMAS, ETC.
XML
(+) Favorecen la interoperabilidad
(+) Paso a través de firewalls
HTTP
(-) Sin embargo, tipos de datos en las
llamadas son más simples…
CLIENTE
SERVIDOR
Lenguaje JAVA
Interfaces definidas en JAVA
Varias máquinas y S.O.
CORBA
RMI
IIOP
CLIENTE
JRMP / IIOP
CLIENTE
TCP/IP
TCP/IP
SERVIDOR
Varios lenguajes: Java, C++…
SERVIDOR
Interfaces definidas en IDL
Interfaces definidas en .NET
Máquinas Windows (?)
A. Goñi. Dpto. LSI, UPV/EHU
Varias máquinas y S.O.
. NET Remoting
Varios lenguajes .NET: C++, C#,
VB.NET …
CLIENTE
(Sustituye a
DCOM)
SERVIDOR
233
HTTP en 5 minutos
• HTTP es un protocolo Cliente/Servidor de
Internet (TCP/IP) del nivel de aplicación, que
proporciona servicios de transmisión de
datos entre aplicaciones.
Petición
SERVIDOR HTTP
CLIENTE HTTP
Respuesta
Ejemplos de comandos en peticiones:
GET Para leer una página Web
POST: Para enviar datos a una página Web
Ejemplos de respuestas:
Estados
Datos
Códigos de error
A. Goñi. Dpto. LSI, UPV/EHU
234
HTTP en 5 minutos
A. Goñi. Dpto. LSI, UPV/EHU
235
HTTP en 5 minutos
[85] sisf00 > telnet sipx55.si.ehu.es 8080
Trying 158.227.112.155...
Connected to sipx55.si.ehu.es.
Escape character is '^]'.
GET /iso/jsp/public_html/pagina.jsp HTTP/1.0
Con telnet se puede abrir un socket
interactivo con un servidor HTTP
Con GET se solicita una página web
(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.)
El servidor HTTP envía datos (protocolo, código respuesta,
<html>
información sobre el servidor,…)
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Prueba</title>
</head>
<body>
<h2> Hola null<br>
Y el contenido de la
Estamos a: Tue May 03 13:28:53 CEST 2005
página HTML
</h2>
</body>
</html>
Connection closed by foreign host.
[65] sisf00 >
A. Goñi. Dpto. LSI, UPV/EHU
236
HTTP en 5 minutos
A. Goñi. Dpto. LSI, UPV/EHU
237
[107] sisf00 > telnet sipx55.si.ehu.es 8080
Trying 158.227.112.155...
Connected to sipx55.si.ehu.es.
Escape character is '^]'.
POST /iso/jsp/public_html/pagina.jsp HTTP/1.0
Content-type: application/x-www-form-urlencoded
Content-length: 14
HTTP en 5 minutosCon el comando POST, se pueden
enviar datos al servidor HTTP.
En este caso es el contenido de un
parámetro, pero en general, puede
ser cualquier fichero.
Nombre=Alfredo
HTTP/1.0 200 OK
Content-Type: text/html;charset=windows-1252
Set-Cookie2: JSESSIONID=crb244gx61;Version=1;Discard;Path="/iso"
Set-Cookie: JSESSIONID=crb244gx61;Path=/iso
Servlet-Engine: Tomcat Web Server/3.2.3 (JSP 1.1; Servlet 2.2; Java 1.3.1_02; Wi
ndows 2000 5.0 x86; java.vendor=Sun Microsystems Inc.)
<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 (eXtensible Markup Language) es
un lenguaje de marcas o etiquetas que
sirve para describir datos
– Definido por el W3C en 1996, a partir de
otro lenguaje: SGML, del cual deriva
también HTML
– HTML es otro lenguaje de marcas
diseñado para mostrar datos
• XML para almacenar, comunicar, no mostrar datos
– Es extensible: se pueden definir nuevas
marcas o etiquetas (tags)
A. Goñi. Dpto. LSI, UPV/EHU
239
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”>
ANIDACIÓN DE MARCAS: toda marca que se cierra debe
corresponder a la última marca abierta y no cerrada
En las etiquetas: MAYÚSCULAS ? minúsculas
ETIQUETAS SIN DATOS ASOCIADOS:
<nombreSala/>
Equivalente a:
<nombreSala></nombreSala>
A. Goñi. Dpto. LSI, UPV/EHU
240
XML en 5 minutos
En un navegador
se puede ver el
fichero XML;
abrir y cerrar
“etiquetas”
A. Goñi. Dpto. LSI, UPV/EHU
Documentos XML bien formados vs.
Documentos XML válidos
241
• 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
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
CLIENTE
Se usa HTTP para la
transmisión de datos XML
entre las aplicaciones
CLIENTE y SERVIDOR
SERVIDOR
POST /gestorBilletes HTTP/1.0
Content-type: text/xml
Content-length: XX
Por ejemplo, para
llamar al método
getBillete(nombre),
podríamos hacerlo así:
A. Goñi. Dpto. LSI, UPV/EHU
<?xml version='1.0' encoding='windows-1252'?>
<llamadaRemota>
<getBillete>
<nombre>Pepe</nombre>
</getBillete>
</llamadaRemota>
242
Se necesita un estándar para enviar
el mensaje con la llamada remota
Se puede definir una estructura de
documento XML que describa una
llamada a un procedimiento remoto
XML
HTTP
CLIENTE
Se usa HTTP para la
transmisión de datos XML
entre las aplicaciones
CLIENTE y SERVIDOR
SERVIDOR
SIN EMBARGO: el documento XML que describe llamadas a procedimientos
remotos debe seguir un estándar si no se quiere construir un servidor distinto
cada vez, para que extraiga los métodos y parámetros
A. Goñi. Dpto. LSI, UPV/EHU
SOAP: Simple Object Access Protocol
243
SOAP: Simple Object Access
Protocol
244
• SOAP 1.2 es recomendación W3C desde
24/3/2004 (http://www.w3.org/TR/soap/)
• Define:
– Formato de mensajes de comunicación en XML
– Cómo debería ser transportado un mensaje vía
Web (HTTP) o e-mail (SMTP)
– Reglas que se siguen cuando se procesa un
mensaje SOAP
– Cómo se convierte una llamada RPC de un cliente
en un mensaje SOAP, cómo se envía al servidor,
cómo se convierte en una llamada RPC en el
servidor, cómo se convierte la respuesta en un
mensaje SOAP y se devuelve al cliente
A. Goñi. Dpto. LSI, UPV/EHU
245
Formato de un mensaje SOAP
SOAP Envelope
SOAP header
Bloque Header
El mensaje se mete en un sobre (envelope)
El mensaje se compone de una cabecera (header)
OPCIONAL y de un cuerpo (Body)
OBLIGATORIO
Bloque Header
SOAP Body
Bloque Body
La cabecera (header) se utiliza para enviar
información sobre identificadores de
transacciones, certificados de seguridad,
información sobre coordinación, etc.
Bloque Body
El cuerpo (body) contiene las llamadas a los
procedimientos remotos (junto con los
parámetros), o bien las respuestas de dichos
procedimientos remotos, o bien información
sobre el error que se haya producido.
A. Goñi. Dpto. LSI, UPV/EHU
246
Ejemplo de llamada SOAP
getNumBillete(“Pepe”)
A. Goñi. Dpto. LSI, UPV/EHU
nom
247
Ejemplo de resultado en SOAP
Resultado de la llamada a
getNumBillete(“Pepe”)
==> 2 (como int)
A. Goñi. Dpto. LSI, UPV/EHU
Se necesita un estándar que
describa el Servicio Web
• ¿Cómo saber qué etiquetas XML
podemos poner en el mensaje SOAP?
<getNumBillete…>
<nom …>
• Es necesario conocer la definición del
servicio Web (esto es, su interfaz)
• Los SW se describen en WSDL
WSDL: Web Services Description
Language
A. Goñi. Dpto. LSI, UPV/EHU
248
WSDL: Web Services Description
Language
249
• WSDL 1.1 es una Nota W3C desde 15/3/2001
(http://www.w3.org/TR/wsdl/)
• Define:
– Una descripción abstracta de un servicio Web
• El sistema de tipos usados para describir los mensajes
(basado en XML Schema)
• Mensajes implicados en invocar una operación
• Operaciones individuales compuestas de distintos patrones de
intercambio de mensajes
• Una interfaz que agrupa las operaciones que forman el servicio
– Una descripción concreta del servicio Web
• El enlace (binding) de la interfaz a un protocolo de transporte
• Dirección o punto de acceso (endpoint) del enlace (binding)
• Descripción de un servicio como una colección de todos los
enlaces (bindings) de la misma interfaz
A. Goñi. Dpto. LSI, UPV/EHU
WSDL: Web Services Description
Language
Documento WSDL
TIPOS DE DATOS USADOS
(los de XML Schema)
DESCRIPCIÓN
ABSTRACTA
DEL SERVICIO
Types
Message
(REQUEST)
Message
(RESPONSE)
Message
(REQUEST)
Message
(RESPONSE)
Operation 2
Operation 1
DESCRIPCIÓN
CONCRETA
DEL SERVICIO
MENSAJES DE
PETICIÓN Y
RESPUESTA
PARA CADA
OPERACIÓN
SERVICIO ABSTRACTO
(CONJUNTO DE
OPERACIONES)
Interface
A. Goñi. Dpto. LSI, UPV/EHU
250
binding 1
binding 2
binding 3
ENLACES A PROTOCOLOS
DE TRANSPORTE
endpoint 1
endpoint 2
endpoint 3
DIRECCIONES DE LOS
ENLACES
Service
TODAS LAS
IMPLEMENTACIONES DEL
SERVICIO
251
WSDL
Types
Message
(REQUEST)
Message
(RESPONSE)
Message
(REQUEST)
Message
(RESPONSE)
Operation 2
Operation 1
Interface
A. Goñi. Dpto. LSI, UPV/EHU
binding 1
binding 2
binding 3
endpoint 1
endpoint 2
endpoint 3
Service
WSDL: Web Services Description
Language
–
Una descripción abstracta de un servicio Web
• El sistema de tipos usados para describir los
mensajes (basado en XML Schema)
•
•
•
–
Mensajes implicados en invocar una operación
Operaciones individuales compuestas de distintos patrones de intercambio de mensajes
Una interfaz que agrupa las operaciones que forman el servicio
Una descripción concreta del servicio Web
•
•
•
El enlace (binding) de la interfaz a un protocolo de transporte
Dirección o punto de acceso (endpoint) del enlace (binding)
Descripción de un servicio como una colección de todos los enlaces (bindings) de la misma interfaz
A. Goñi. Dpto. LSI, UPV/EHU
types
252
WSDL: Web Services Description
Language
–
Una descripción abstracta de un servicio Web
•
El sistema de tipos usados para describir los mensajes (basado en XML Schema)
• Mensajes implicados en invocar una
operación
•
•
–
message
Operaciones individuales compuestas de distintos patrones de intercambio de mensajes
Una interfaz que agrupa las operaciones que forman el servicio
Una descripción concreta del servicio Web
•
•
•
El enlace (binding) de la interfaz a un protocolo de transporte
Dirección o punto de acceso (endpoint) del enlace (binding)
Descripción de un servicio como una colección de todos los enlaces (bindings) de la misma interfaz
A. Goñi. Dpto. LSI, UPV/EHU
253
WSDL: Web Services Description
Language
–
Una descripción abstracta de un servicio Web
•
El sistema de tipos usados para describir los mensajes (basado en XML Schema)
•
Mensajes implicados en invocar una operación
• Operaciones individuales compuestas de distintos
operation
patrones de intercambio de mensajes
• Una interfaz que agrupa las operaciones que forman el portType
servicio
–
Una descripción concreta del servicio Web
•
•
•
El enlace (binding) de la interfaz a un protocolo de transporte
Dirección o punto de acceso (endpoint) del enlace (binding)
Descripción de un servicio como una colección de todos los enlaces (bindings) de la misma interfaz
A. Goñi. Dpto. LSI, UPV/EHU
254
WSDL: Web Services Description
Language
–
Una descripción abstracta de un servicio Web
•
–
El sistema de tipos usados para describir los mensajes (basado en XML Schema)
• Mensajes implicados en invocar una operación
• Operaciones individuales compuestas de distintos patrones de intercambio de mensajes
• Una interfaz que agrupa las operaciones que forman el servicio
Una descripción concreta del servicio Web
• El enlace (binding) de la interfaz a un protocolo de
transporte
•
•
A. Goñi. Dpto. LSI, UPV/EHU
binding
Dirección o punto de acceso (endpoint) del enlace (binding )
Descripción de un servicio como una colección de todos los enlaces (bindings) de la misma
interfaz
255
256
WSDL: Web Services Description
Language
–
Una descripción abstracta de un servicio Web
•
–
El sistema de tipos usados para describir los mensajes (basado en XML Schema)
• Mensajes implicados en invocar una operación
• Operaciones individuales compuestas de distintos patrones de intercambio de mensajes
• Una interfaz que agrupa las operaciones que forman el servicio
Una descripción concreta del servicio Web
• El enlace (binding) de la interfaz a un protocolo de transporte
• Dirección o punto de acceso (endpoint) del enlace (binding)
• Descripción de un servicio como una colección de todos los
enlaces (bindings) de la misma interfaz
A. Goñi. Dpto. LSI, UPV/EHU
port
service
257
Punto de acceso (endpoint)
al SW
A. Goñi. Dpto. LSI, UPV/EHU
258
A. Goñi. Dpto. LSI, UPV/EHU
259
RESULTADO
Mensaje
SOAP con la
respuesta
A. Goñi. Dpto. LSI, UPV/EHU
260
Usar SW en JDeveloper
• Afortunadamente, los distintos entornos
ofrecen herramientas y asistentes que
generan los WSDL y SOAP de manera
automática, a partir de clases
implementadas en distintos Leng. Prog.
• Los programadores pueden seguir
trabajando con sus lenguajes y
plataformas habituales
• JDeveloper, en concreto, lo permite
A. Goñi. Dpto. LSI, UPV/EHU
261
Crear un SW en Java
A. Goñi. Dpto. LSI, UPV/EHU
Se selecciona la clase Java para la
que se quiere crear el SW
A. Goñi. Dpto. LSI, UPV/EHU
262
Seleccionar los métodos que se
quieren publicar en el SW
¡Cuidado! No se pueden crear SW para
métodos cuyos tipos no sean los básicos, String,
Date, Calendar,… o Array[] de ellos
A. Goñi. Dpto. LSI, UPV/EHU
263
Se indica la dirección del punto de
acceso
A. Goñi. Dpto. LSI, UPV/EHU
264
El WSDL se genera automáticamente
A. Goñi. Dpto. LSI, UPV/EHU
265
266
Punto
acceso
A. Goñi. Dpto. LSI, UPV/EHU
Creamos una clase Java cliente del SW
A. Goñi. Dpto. LSI, UPV/EHU
267
268
A. Goñi. Dpto. LSI, UPV/EHU
269
Añadimos el código con la
llamada al SW (en Java)
A. Goñi. Dpto. LSI, UPV/EHU
270
Ejecutamos el SW
A. Goñi. Dpto. LSI, UPV/EHU
271
Ejecutamos el
cliente del SW
A. Goñi. Dpto. LSI, UPV/EHU
272
Y activamos el Monitor TCP
para ver los mensajes SOAP
Tools => TCP Packet Monitor
A. Goñi. Dpto. LSI, UPV/EHU
273
Mensaje SOAP con la
petición
A. Goñi. Dpto. LSI, UPV/EHU
Mensaje SOAP con la
respuesta
274
Otros temas
• UDDI (Universal Description, Discovery and Integration)
– Es un directorio distribuido donde las empresas pueden registrar,
eliminar y buscar servicios web.
– Empresas como IBM, Microsoft, etc. mantienen nodos con esa
información.
• Se pretende construir una infraestructura para construir
aplicaciones integrando servicios web entre empresas (B2B)
• Herramientas para traducir de WSDL a un lenguaje (Java,
lenguaje .NET, …)
– Apache AXIS proporciona compiladores Java a WSDL y de WSDL
a Java
• Definición de otros estándares como WS-Coordination, WSTransaction, WS-Routing
– ¿Qué pasa si se quiere reservar un viaje completo?
• Reservar vuelo => Usando SW
• Reservar hotel => Usando SW
• ¿Y si quisiéramos que fuera una transacción?
A. Goñi. Dpto. LSI, UPV/EHU
275
Ejercicio de Arquitecturas
Software
A. Goñi. Dpto. LSI, UPV/EHU
276
La interfaz de usuario
asociada a un caso de
uso llamado
CONSULTAR PRECIO
aparece a continuación,
junto con la clase Java
correspondiente:
A. Goñi. Dpto. LSI, UPV/EHU
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(); } }
// Continúa…
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) {...}
A. Goñi. Dpto.
} LSI, UPV/EHU
277
278
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
A. Goñi. Dpto. LSI, UPV/EHU
279
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; }
A. Goñi. Dpto. LSI, UPV/EHU
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”.
A. Goñi. Dpto. LSI, UPV/EHU
280
281
Solución
ConsPrecioIU
p: PreciosLN
“interface” PreciosLN
usa calcularPrecio(c1,c2,c3: String): float
Precios
inicializarBD(): void
getPrecio(nombre:String): float
calcularPrecio(kgMan,kgPer,kgNar: String) : float
A. Goñi. Dpto. LSI, UPV/EHU
EN LA PRESENTACIÓN AÑADIMOS UN ATRIBUTO
CON LA LÓGICA DEL NEGOCIO Y MÉTODO PARA
ASIGNARLA:
282
public class ConsPrecioIU extends Frame {
…
PreciosLN pr;
void setLogicaNegocio(PreciosLN p) {pr=n;}
…}
LA LÓGICA DEL NEGOCIO SE DEFINE CON UNA INTERFAZ:
public interface PreciosLN {
public float calcularPrecio(String kgManz,
String kgPer,
String kgNar);
}
A. Goñi. Dpto. LSI, UPV/EHU
283
LA LÓGICA DEL NEGOCIO SE USA DESDE EL
MÉTODO DE ATENCIÓN AL EVENTO
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);
}
A. Goñi. Dpto. LSI, UPV/EHU
284
public class Precios implements PreciosLN {
public float calcularPrecio(String kgManz,
String kgPer,
String kgNar) {
float m,p,n;
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;}
return m*getPrecio("MANZANAS (Kg.)")+
p*getPrecio("PERAS (Kg.)")+
n*getPrecio("NARANJAS (Kg.)");}
// y los métodos inicializarBD y getPrecio…
}
LA LÓGICA DEL NEGOCIO SE OBTIENE
IMPLEMENTANDO LA INTERFAZ. PARA ELLO
SE REALIZAN LLAMADAS AL NIVEL DE DATOS
A. Goñi. Dpto. LSI, UPV/EHU
285
Es una solución correcta…
• La solución sigue una arquitectura lógica en
tres niveles (están separadas el nivel de
presentación del nivel lógica del negocio en
clases y el nivel de datos en la BD)
– Presentación: ConsPrecioIU y Aviso
– Lógica del negocio: interfaz PreciosLN y clase Precios
• Es extensible
– Cuando se quiera añadir la regla del negocio para aplicar
descuentos según la cantidad comprada habrá que
reprogramar la clase calcularPrecios de la lógica del
negocio y la BD (para almacenar descuentos, etc.). Pero
NO CAMBIARÁ la clase de presentación
A. Goñi. Dpto. LSI, UPV/EHU
La siguiente solución no es
correcta…
“interface” PreciosLN
ConsPrecioIU
p: PreciosLN
usa
getPrecioMan(): float
getPrecioPer(): float,
getPrecioNar(): float
Precios
inicializarBD(): void
getPrecio(nombre:String): float
getPrecioMan(): float
getPrecioPer(): float,
getPrecioNar(): float
A. Goñi. Dpto. LSI, UPV/EHU
286
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
La solución propuesta, sin embargo,
no es extensible si se desea cambiar el
número y el nombre de productos
(lo cual no se pedía en el
enunciado…)
A. Goñi. Dpto. LSI, UPV/EHU
289
• Una solución extensible ante el
posible cambio “se pueden
consultar los precios de varios
productos” aparece a continuación.
• Para ver si una solución es
extensible hay que saber con
respecto a qué posible cambio es
extensible
A. Goñi. Dpto. LSI, UPV/EHU
void button1_actionPerformed(ActionEvent e) {
// En p tenemos el objeto con la lógica del negocio
Vector datos= new Vector();
datos.addElement(label1.getText());
datos.addElement(textField1.getText());
datos.addElement(label2.getText()); // …
float precio = p.calcularPrecio(datos.elements());
Aviso a = new Aviso(this,"Precio es: "+precio);
}
“interface” PreciosLN
ConsPrecioIU
p: PreciosLN
usa
calcularPrecio(datos: Enumeration): float
obtenerProductos(): Enumeration
Precios
inicializarBD(): void
getPrecio(nombre:String): float
calcularPrecio(PrecCant:Enumeration ) : float
obtenerProductos(): Enumeration
A. Goñi. Dpto. LSI, UPV/EHU
290