Está en la página 1de 290

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
7
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
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();
b.setVisible(true);}}
A. Goñi. Dpto. LSI, UPV/EHU
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();
b.setVisible(true);}}
A. Goñi. Dpto. LSI, UPV/EHU
10

public class PedirBilleteNO3NIVELES extends JFrame {


// Nota: NO ESTÁ COMPLETA !!
JLabel jLabel1 = new JLabel(“Nombre:”);
ACCESO A
JButton jButton1 = new JButton(“Pedir Billete”);
public PedirBilleteNO3NIVELES() {
DATOS
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();
b.setVisible(true);}}
A. Goñi. Dpto. LSI, UPV/EHU
LÓGICA DEL NEGOCIO 11

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();
b.setVisible(true);}}
A. Goñi. Dpto. LSI, UPV/EHU
12

Arquitectura lógica del


software en niveles
ES MEJOR SEPARAR EL CÓDIGO EN
NIVELES: USAR CLASES DISTINTAS
NIVEL DE NIVEL DE LÓGICA NIVEL DE
PRESENTACIÓN DEL NEGOCIO DATOS
public class GB
Nombre: implements GestorBilletes {
... SELECT ...
public Billete getBillete INSERT ...
Pedir Billete (String nom) {...}

CLASES CON OPERACIONES


PROPIAS DEL NEGOCIO
INTERFAZ GRÁFICO DE
USUARIO: - inicializarSala
Frame o Applet - getBillete,...
BASE DE DATOS
Aquí se pueden aplicar reglas del
negocio: por cada 10 billetes
A. Goñi. Dpto. LSI, UPV/EHU comprados se regala uno, etc...
13
Arquitectura lógica del
software en niveles
• 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 16

(análisis) del PUD siguen filosofía 3


niveles

NIVEL DE NIVEL DE
PRESENTACIÓN DATOS

NIVEL DE LÓGICA
DEL NEGOCIO

A. Goñi. Dpto. LSI, UPV/EHU


17
Los diagramas de colaboración (análisis)
del PUD siguen filosofía 3 niveles

• Clases FRONTERA NIVEL DE PRESENTACIÓN

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

getBillete(nombre) Datos
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, "")

A. Goñi. Dpto. LSI, UPV/EHU


19
Arquitectura física del
software en niveles
• 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 SERVIDOR

NIVEL DE NIVEL DE LÓGICA NIVEL DE


PRESENTACIÓN DEL NEGOCIO 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 BD Datos
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…";); SERVIDOR
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
22

CLIENTE Sentencia SQL


CLIENTE
CLIENTE Respuesta
Driver
CLIENTE
CLIENTE
BD
dbcDriver CLIENTE
CLIENTE
OdbcDriver CLIENTE
CLIENTE
c.JdbcOdbcDriver CLIENTE
bc.JdbcOdbcDriver CLIENTE
CLIENTE SERVIDOR
bc.odbc.JdbcOdbcDriver CLIENTE
n.jdbc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver CLIENTE ¡¡ CADA CLIENTE
CLIENTE
sun.jdbc.odbc.JdbcOdbcDriver UNA CONEXIÓN
sun.jdbc.odbc.JdbcOdbcDriver ABIERTA CON LA
sun.jdbc.odbc.JdbcOdbcDriver
BD!!
A. Goñi. Dpto. LSI, UPV/EHU
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
24
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 SERVIDOR

NIVEL DE NIVEL DE NIVEL DE


PRESENTACIÓN LÓGICA DEL DATOS + LÓGICA
NEGOCIO 1 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
25

Arquitectura física en 3 niveles

CLIENTE CLIENTE CLIENTE Nivel de Presentación

Nivel de Lógica del Negocio


SERVIDOR SERVIDOR (en SERVIDORES DE
APLICACIONES)

Nivel de Datos

BASE DE
DATOS

A. Goñi. Dpto. LSI, UPV/EHU


26
CLIENTE
public class PedirBillete extends JFrame { BD Datos
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");} } SERVIDOR
DATOS

SERVIDOR APLICACIONES
INSTALAR LA public class ServidorGestorBilletesBD
CLASE implements GestorBilletes Lógica del Negocio
sun.jdbc.odbc. { public ServidorGestorBilletesBD() {
JdbcOdbcDriver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
Y DEFINIR public Billete getBillete(String nom)
FUENTE {ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
DATOS ODBC int act = sent.executeUpdate("UPDATE BILLETES …“);
“Billetes” if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
A. Goñi. Dpto. LSI, UPV/EHU
27

BD
sun.jdbc.odbc.JdbcOdbcDriver

SERVIDOR
CLIENTE APLICACIONES
CLIENTE
CLIENTE sun.jdbc.odbc.JdbcOdbcDriver SERVIDOR
CLIENTE SERVIDOR
CLIENTE APLICACIONES DATOS
CLIENTE
CLIENTE
CLIENTE SERVIDOR
CLIENTE APLICACIONES
CLIENTE
CLIENTE sun.jdbc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE
CLIENTE ¡¡ SÓLO LOS SERVIDORES
CLIENTE DE APLICACIONES TIENEN
CLIENTE CONEXIONES ABIERTAS
CLIENTE
CON LA BD!!
A. Goñi. Dpto. LSI, UPV/EHU
28

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
29
Las aplicaciones Web permiten más
niveles
CLIENTE CLIENTE CLIENTE CLIENTE Nivel de
(Nav. Web) (Nav. Web) (Nav. Web) (Nav. Web) Presentación
(ejecución)
SERVIDOR SERVIDOR SERVIDOR
WEB WEB WEB
Nivel de Presentación
(instalación)

SERVIDOR SERVIDOR Nivel de Lógica del Negocio


APLICACIONES APLICACIONES

Nivel de Datos

BASE DE
A. Goñi. Dpto. LSI, UPV/EHU DATOS
30

CLIENTE SERVIDOR
BD Datos
WEB
Navegador
HTML + JSP +
Web
Bean
Ejecutar Instalar
Presentación Presentación
SERVIDOR
DATOS

SERVIDOR APLICACIONES
INSTALAR LA public class ServidorGestorBilletesBD
CLASE implements GestorBilletes Lógica del Negocio
sun.jdbc.odbc. { public ServidorGestorBilletesBD() {
JdbcOdbcDriver Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");}
Y DEFINIR public Billete getBillete(String nom)
FUENTE {ResultSet rs = sent.executeQuery("SELECT NUMERO…";);
DATOS ODBC int act = sent.executeUpdate("UPDATE BILLETES …“);
“Billetes” if (act>0) return new Billete(n,nom); // Núm. billete asignado
else return new Billete(-1,"");; } // No había ninguno libre}}}
A. Goñi. Dpto. LSI, UPV/EHU
31
BD
sun.jdbc.odbc.JdbcOdbcDriver

SERVIDOR
APLICACIONES

sun.jdbc.odbc.JdbcOdbcDriver
SERVIDOR
APLICACIONES

CLIENTE SERVIDOR WEB


CLIENTE SERVIDOR
CLIENTE APLICACIONES SERVIDOR
CLIENTE DATOS
sun.jdbc.odbc.JdbcOdbcDriver
CLIENTE
CLIENTE SERVIDOR WEB
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE
CLIENTE EN LOS CLIENTES NO HAY
CLIENTE QUE INSTALAR NADA
CLIENTE (EXCEPTO NAVEGADOR
CLIENTE
CLIENTE WEB+ INTERNET)
CLIENTE

A. Goñi. Dpto. LSI, UPV/EHU


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
34
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
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 Contenedor

Clase Contenedor ContConc1 ContConcM


add (Componente c) Un contenedor se compone de varios
componentes, los cuales pueden ser
-- el método add añade componentes concretos o pueden ser
-- componentes contenedores. Estos contenedores pueden estar
-- al contenedor a su vez compuestos de varios componentes.
A. Goñi. Dpto. LSI, UPV/EHU
41

La jerarquía de clases de AWT sigue


un patrón de diseño COMPOSITE
COMPONENTE

Applet
CONTENEDOR
(todo contenedor es
Las posibilidades son infinitas…
un componente)
- Una ventana formada por 2 cajas de texto, 2 campos de texto, 3 botones, 1
panel que contenga 5 casillas de validación y una lista desplegable.
-Una ventana formada por 2 etiquetas, 2 campos de texto y un botón
-…
Además, añadir nuevos tipos de contenedores y de componentes no sería muy
costoso (estaríamos ante una solución extensible)
A. Goñi. Dpto. LSI, UPV/EHU
42

Un diseño de clases como este sería


francamente malo …
Button *
*
CheckBox

* Frame
TextField
* …
- Se necesitarían métodos addButton, addCheckBox, addTextField,
addFrame en la clase Frame (y los correspondientes a todos los que faltan)
- Además el diagrama está muy incompleto, ya que un Button puede ser
componente de un Panel, Dialog, …
- Si se quisiera añadir un nuevo componente XXX, habría que cambiar la
clase Frame y añadir el método addXXX (nada extensible)
A. Goñi. Dpto. LSI, UPV/EHU
43

Componentes principales de Swing

Applet
JComponent JMenuBar
JWindow
JFrame JTextField,
JDialog
JPanel JList JComboBox JTextArea,
JApplet JButton…

A. Goñi. Dpto. LSI, UPV/EHU


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
jPanel3
jPanel2 jRadioButton2

jTextArea1

jButton1
jPanel1

A. Goñi. Dpto. LSI, UPV/EHU


47
Componentes principales
de AWT / Swing

• 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
49
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


50

JFrame

A. Goñi. Dpto. LSI, UPV/EHU


51
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
52

A. Goñi. Dpto. LSI, UPV/EHU


53
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
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


57
Componentes principales
de AWT / Swing

• 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


59
JTable para mostrar y
JTable editar tablas de datos

Se puede
redimensionar…

Modificar valores
en celdas…

A. Goñi. Dpto. LSI, UPV/EHU


60
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
61

Menús en Swing
JMenu
JMenu

JMenuBar

JMenuItem JMenuItem

A. Goñi. Dpto. LSI, UPV/EHU


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
66

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 y anchura altura
A. Goñi. Dpto. LSI, UPV/EHU
67

Label Panel
en BorderLayout.NORTH 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 obj2 contiene una referencia a un


OBJETO GRÁFICO (botón, objeto de una clase que implementa
ventana, lista desplegable, el interface XXXListener.
checkbox, etc) sobre el que se public interface XXXListener {
quiere definir un ....
comportamiento ante EVENTOS void accionYYY (AWTEvent e);
}

En tiempo de Se crea un objeto El objeto oyente ejecutará el


ejecución sucede evento(AWTEvent) método correspondiente a la
un EVENTO y se pasa el control acción (Ej.: accionYYY)
que afecta al al objeto oyente usando el objeto Evento
objeto de obj1 (el de obj2) generado como parámetro
A. Goñi. Dpto. LSI, UPV/EHU
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
83
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
84

2) Seleccionar el
Evento
(actionPerformed)
1) Hacer click en el componente 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
86
JDeveloper genera las clases Oyente como
INNER CLASS sin nombre

Tras pulsar
el botón

A. Goñi. Dpto. LSI, UPV/EHU


87

Definición de una clase


SIN NOMBRE que
implementa el interface
ActionListener

button1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
button1_actionPerformed(e);
ESTE CÓDIGO }
SE GENERA DE });
MANERA LA ACCIÓN HAY QUE
AUTOMÁTICA PROGRAMARLA, CLARO
CON JDeveloper
void button1_actionPerformed(ActionEvent e) {
textArea1.setText("Opción: "+checkboxGroup1.getCurrent().getLabel());
}
A. Goñi. Dpto. LSI, UPV/EHU
88

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
Inicialmente… Cuando entra el ratón en el botón91

Punto donde se
encuentra el ratón

Al hacer “drag” dentro del botón Al salir el ratón del botón

A. Goñi. Dpto. LSI, UPV/EHU


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 jTextArea1
área de texto.
A. Goñi. Dpto. LSI, UPV/EHU
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
En alguno de los métodos de la clase
Presentación (los que responden a eventos)
se usará:
setLogicaNegocio
logNe.hacerX(…)
(l: LogicaNegocio)
o bien
logNe.hacerY(…)

A. Goñi. Dpto. LSI, UPV/EHU


96
Interface LogicaNegocio

hacerX(… )
hacerY(… )
usa
Clase Presentacion
logNe: LogicaNegocio
clase LogicaNegocioConcreta

hacerX(… ) // Implementada
setLogicaNegocio hacerY(… ) // Implementada
(l: LogicaNegocio)

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

Clase Presentacion Interface LogicaNegocio


usa
logNe: LogicaNegocio hacerX(… )
hacerY(… )

setLogicaNegocio
(l: LogicaNegocio) clase LogicaNegocionNueva

hacerX(… ) // Implementada
hacerY(… ) // Implementada
Si ahora se quisiera cambiar la lógica del negocio, bastaría con
hacer: p.setLogicaNegocio(new LogicaNegocioNueva());
NO HACE FALTA RECOMPILAR LA CLASE Presentacion,
y, si se conoce la referencia del objeto, SE PUEDE CAMBIAR
LA LÓGICA DEL NEGOCIO EN TIEMPO DE EJECUCIÓN
A. Goñi. Dpto. LSI, UPV/EHU
98

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

Clase PedirBillete Interface GestorBilletes


usa
gestorBilletes: getBillete(String):int
GestorBilletes

setGestorBilletes
(GestorBilletes) 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 JDBC-
ODBC para convertir llamadas JDBC a
ODBC y poder acceder así a BDs que ya
tienen un driver ODBC mediante JDBC
– En el caso de hacerlo así, hay que registrar la BD
correspondiente para ser usada con ODBC
A. Goñi. Dpto. LSI, UPV/EHU
105

Arquitectura para JDBC: 4 tipos de drivers


Aplicación JAVA

API de JDBC

JDBC Driver Manager

API de JDBC Driver

Driver puente Distintos tipos de Driver JDBC:


JDBC-ODBC Driver JDBC A) Traduce a APIs nativas del
SGBD.
B) Se comunica con aplicación
Driver ODBC intermedia en el servidor
que traslada peticiones al
SGBD SGBD que se trate
SGBD C) Se comunica directamente
con el SGBD
A. Goñi. Dpto. LSI, UPV/EHU
106

APLICACIÓN Connection c;

Cargar Driver SGBD X

Abrir Conexión BD 1 BD 1

Enviar/
Crear Statement Recibir
SQL

Enviar Sentencia 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

3 2 Agregar y escoger “MAccess Driver”

4
Seleccionar una BD
Access previamente
creada
A. Goñi. Dpto. LSI, UPV/EHU
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

Clase PedirBillete Interface GestorBilletes


usa
gestorBilletes: getBillete(String):int
GestorBilletes

setGestorBilletes
(GestorBilletes) 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 OBJETOS
Persona juan:Persona elena:Persona
dni: int 17832423 17114452
nombre: String “Juan Pérez” “Elena Pérez”
suCoche: Coche coche1 coche1
Coche
coche1:Coche
matricula: String
modelo: String 3541 CGH
susProp: Vector “Citroen C4”
<juan,elena>

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 135

objetos en el fichero personas.txt…


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 139

objetos en el fichero personas.dat…


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 140

por la red …
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

Clase PedirBillete Interface GestorBilletes


usa
gestorBilletes: getBillete(String):int
GestorBilletes

setGestorBilletes
(GestorBilletes) clase ServidorGestorBilletesSerializado

getBillete(String):int
inicializarSala(int)
escribir()
leer()
A. Goñi. Dpto. LSI, UPV/EHU
Nueva lógica del negocio para144 el
ejemplo de PEDIR BILLETES.
Se pide el billete a un servidor
(que se encuentra en la máquina
“host”) por medio de un
SOCKET. Se usan mecanismos
de SERIALIZACIÓN para el
paso de parámetros y recogida
de resultados.

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

Clase PedirBillete Interface GestorBilletes


usa
gestorBilletes: getBillete(String):int
GestorBilletes

setGestorBilletes
clase GestorBilletesCliente
(GestorBilletes)
getBillete(String):int

En distintos ordenadores

clase ServidorGestorBilletesBD socket


getBillete(String):int
inicializarSala(int) clase Servidor
usa
crearTablaBilletes()

A. Goñi. Dpto. LSI, UPV/EHU


147

5. Introducción a la
computación distribuida con
Java RMI

A. Goñi. Dpto. LSI, UPV/EHU


148
Í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
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 GestorBilletes
Clase Cliente1
.... - listaBilletes: Vector
- maxBilletes: int
+ getGestor(): GestorBilletes
+ getBillete(nom: String): int
Clase ClienteN // Dev. nº billete asignado o -1 si no hay
....
-- Clase con 1 sola instancia (Singleton)
-- El método static getGestor() la devuelve
EN NODOS CLIENTE EN EL NODO SERVIDOR
No es posible realizar lo siguiente en una clase cliente:

GestorBilletes g = GestorBilletes.getGestor();
return g.getBillete("Kepa Sola");

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


// Dev. nº billete asignado o -1 si no hay
ClienteN
....
-- 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
{
Interfaz java.rmi.Remote
public int getBillete(String nom)
throws RemoteException;
-- INTERFAZ REMOTA
}

GestorBilletes.java Interfaz GestorBilletes


realiza + 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 Interfaz java.rmi.Remote

-- CLASE REMOTA -- INTERFAZ REMOTA

extiende extiende
Clase ServidorGestorBilletes implementa Interfaz GestorBilletes
+ getBillete(nom: String): int + 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
155
Servidor Remoto
// 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 Interfaz java.rmi.Remote

-- CLASE REMOTA -- INTERFAZ REMOTA

extiende extiende
Clase ServidorGestorBilletes implementa Interfaz GestorBilletes
+ getBillete(nom: String): int + getBillete(nom: String): int
-- CLASE REMOTA -- INTERFAZ REMOTA

La clase cliente:
usa
• busca el objeto remoto que le proporciona
el servicio que le interesa. Para ello debe
Clase Cliente
conocer el nombre del servicio, pero no la ges : GestorBilletes
clase remota (no hace new) -- CLASE CLIENTE
• pide a dicho objeto que ejecute un método
remoto (definido en la interfaz remota)
A. Goñi. Dpto. LSI, UPV/EHU
158

//
Cliente
Cliente.java
import java.rmi.*;

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") objRemoto @ObjLocalX

RETURN: 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 Programa Servidor
call return call return

Stub Skeleton

Nivel de Nivel de
Referencia Remota Referencia Remota
Nivel de Nivel de
Transporte Transporte

Conexión TCP/IP
Los objetos Stub y Skeleton se
encargan de realizar la conexión y del
paso de parámetros y resultados.
A. Goñi. Dpto. LSI, UPV/EHU
162

Arquitectura RMI
GestorBilletes objRemoto =
(GestorBilletes)Naming.lookup("rmi://IPServidor/gestorBilletes");
lookup BUSCA y
objRemoto.getBillete("Koldo");
OBTIENE el objeto STUB

@ObjStubX Objeto STUB de la clase


ServidorGestorBilletes_Stub

getBillete Máquina virtual java CLIENTE


"Koldo" RETURN: 5
Máquina virtual java SERVIDOR

@ObjSkelY Objeto SKELETON de la clase


ServidorGestorBilletes_Skeleton

objServidor @ObjServY Objeto de la clase


ServidorGestorBilletes
objServidor.getBillete("Koldo")
A. Goñi. Dpto. LSI, UPV/EHU
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

puerto 1099 Máquina virtual java situada en IPServidor

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 mainServidorGestorBilletesBD


máquina (IPServidor), pero cada uno en DISTINTAS
MÁQUINAS VIRTUALES JAVA objRemoto:ServidorGestorBillet new
esBD
RmiRegistry está escuchando en un puerto (1099)

Mirar métodos de LocateRegistry.createRegistry


Naming exportObject(PuertoAnonimo)

stub: ServidorGestorBilletesBD
Rmiregistry rebind("localhost:1099/gestorBilletes",objRemoto)
_Stub

getRef()
new(referenciaAObjRemoto)

referenciaAObjRemoto

: PedirBillete
Naming SOCKET("localhost",1099,"gestorBilletes",stub)

lookup("rmi://IpServidor:1099/gestorBilletes")
SOCKET("IPservidor",1099,"gestorBilletes") Se pasa el objeto STUB serializado.
El cliente cargará dinámicamente la clase
ServidorGestorBilletesBD_Stub
SOCKET(stub)

stub
stub: ServidorGestorBilletesBD
_Stub
getBillete("Pepe")

SOCKET("IPServidor",PuertoAnonimo,"gestorBilletes","getBillete","Pepe")

numBilleteParaPepe
SOCKET(numBilleteParaPepe)

PresentacionRemoto en otra máquina


A. Goñi. Dpto. LSI, UPV/EHU
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


172
Servidor Remoto accede a BD
// 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
173
Servidor Remoto accede a BD
public int getBillete(String nom)
throws RemoteException {
// Devuelve nº billete, -1 si no hay, -2 si hay problemas
String pregSQL = "SELECT NUM FROM BILLETES”+
" WHERE ESTADO='LIBRE'";
try{ ResultSet rs = sentencia.executeQuery(pregSQL);
if (rs.next()) {
String num = rs.getString("NUM");
int act = sentencia.executeUpdate("UPDATE BILLETES"+
" SET ESTADO='OCUPADO', NOMBRE = '"+nom+
"' WHERE NUM="+num+" AND ESTADO='LIBRE'");
conexion.commit();
int n= Integer.parseInt(num);
if (act>0) return n; // Núm. billete asignado
return -2; } // Otro ya ha OCUPADO ese billete
else return -1; } // No había ninguno libre
catch (SQLException e)
{System.out.println("Error: "+e.toString());}
return -2; // Que prueben otra vez a llamar
} A. Goñi. Dpto. LSI, UPV/EHU
174
Servidor Remoto accede a BD
// Método main de ServidorGestorBilletesBD.java
public static void main(String[] args) {

System.setSecurityManager(new RMISecurityManager());
try {
ServidorGestorBilletesBD objetoServidor =
new ServidorGestorBilletesBD();

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
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
176
ARQUITECTURA FÍSICA Interface LogicaNegocio
EN 2 NIVELES:
CLIENTE GORDO / SERVIDOR FLACO hacerX(… )
hacerY(… )
Clase Presentacion usa
logNe: LogicaNegocio

setLogicaNegocio
clase LogicaNegocioConcreta
(l: LogicaNegocio)
// Permite cambiar lógica hacerX(…) // Implementaciones
// negocio en tº ejecuc. hacerY(…) // llaman al nivel de
-- En esta clase se llama // datos (usan JDBC)
-- a la lógica del negocio:
Por ej.: logNe.hacerX(…)
CREAR LA INTERFAZ GRÁFICA Y ASIGNAR LÓGICA DEL NEGOCIO:
Presentacion p = new Presentacion();
p.setLogicaNegocio(new LogicaNegocioConcreta());
p.setVisible(true);
A. Goñi. Dpto. LSI, UPV/EHU
177
ARQUITECTURA FÍSICA Interface LogicaNegocio
EN 3 NIVELES
usando RMI hacerX(… )
hacerY(… )
Clase Presentacion
usa interfaz Remota
logNe: LogicaNegocio

setLogicaNegocio
clase LogicaNegocioConcreta
(String nombreServicio)
// Por ejemplo aquí se hacerX(…) // Implementaciones
// puede asignar a logNe hacerY(…) // llaman al nivel de
-- En esta clase se llama // datos (usan JDBC)
-- a la lógica del negocio:
-- La lógica del negocio se crea
Por ej.: logNe.hacerX(…)
-- y se exporta usando:
-- Para asignar la lógica
Naming.rebind y dando un
-- del negocio se usa
nombre de servicio: NomSer
Naming.lookup y NomSer
A. Goñi. Dpto. LSI, UPV/EHU
178

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/jinstall-
1_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
187
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
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
192
¿Validar la entrada es nivel de
presentación o lógica del negocio?
• Validar la entrada tiene que ver con la
presentación, con la interacción con el usuario,
que ha escrito mal los datos: debe hacerse en
el nivel de presentación
• Sin embargo, a veces no está tan clara la
diferencia entre nivel de presentación y lógica
del negocio
• En una aplicación Web no importa tanto, ya
que el nivel de presentación “se instala” en el
lado del servidor y se ejecuta en los clientes.
Cambiar la lógica del negocio o presentación
NO requiere reinstalar los clientes
• Regla a observar: intuir cambios futuros y
hacer el software extensible ante esos cambios
A. Goñi. Dpto. LSI, UPV/EHU
193

Servlets

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> out: objeto con la
<H1> Adiós </H1>
</body></html>
salida HTML
A. Goñi. Dpto. LSI, UPV/EHU
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


210
<html><body> Recoger datos de formularios
<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
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 211
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date(); MOSTRAR
int numAccesos = 0;
%> LA SALIDA
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img> CON HTML
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- Comentario HTML: aparece como comentario en el HTML, pero no se verá en el
navegador del cliente. A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 212
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date();
int numAccesos = 0;
%>
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img>
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer.
Este comentario se verá en el navegador del cliente --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
<%-- Comentario JSP: no aparece en el HTML, pero sí en el SERVLET --%> 213
<%-- Usamos JSP directive para importar paquetes Java: --%>
<%@ page import="java.util.*" %>
<%-- Declaraciones JSP: se ejecutan sólo cuando se carga el servlet: --%>
<%!
long tiempoDeCarga= System.currentTimeMillis();
Date fechaDeCarga = new Date();
int numAccesos = 0;
%>
<html><body>
<img SRC="imagenReloj.jpg" height=218 width=291></img>
<%-- A continuación se usan expresiones JSP --%>
<H1>Fecha de la primera carga de la página: <%= fechaDeCarga %> </H1>
<H1>Fecha actual: <%= new Date() %></H1>
<H2>Página activa <%= (System.currentTimeMillis()-tiempoDeCarga)/1000 %> segs</H2>
<H3>Página accedida <%= ++numAccesos %> veces desde <%= fechaDeCarga %></H3>
<%-- Un "scriptlet" que escribe en la salida estándar del servidor
y en la página visualizada por el cliente.
Es código Java, y se usa la variable predefinida "out"--%>
<%
System.out.println("Adiós (no se verá en el navegador)");
out.println("Agur (se verá en el navegador)");
%>
<P> <!-- A continuación hay código HTML para que se cargue un sonido
en la página y que funcione en Netscape y en Internet Explorer.
Este comentario se verá en el navegador del cliente --%>
<EMBED SRC="bong.wav" HIDDEN="true" AUTOSTART="true">
<NOEMBED>
<BGSOUND SRC="bong.wav">
</NOEMBED>
<P> <a href="bong.wav"> Haz click en este link y oirás el sonido también </a>
</body></html>
A. Goñi. Dpto. LSI, UPV/EHU
También se puede validar la entrada 214
en el nivel de presentación con JSPs y
JavaScript
• Más eficiente: sólo se llama a la lógica
del negocio con entradas correctas
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<TITLE>PEDIR BILLETE</TITLE></HEAD>
<BODY>
<H1> PEDIR BILLETE </H1>
<FORM NAME="LE" METHOD="post" ACTION="PedirBillete.jsp">
Nombre: <INPUT TYPE="text" NAME="nombre" onChange=validar();><P>
<INPUT TYPE="submit" value="Pedir Billete" >
<INPUT type="reset" VALUE="Borrar Datos">
</FORM>
<SCRIPT LANGUAGE="JavaScript">
function validar()
{var nombre = document.LE.nombre.value;
if (nombre.length<5) alert("Error, menos de 5 letras:" +
document.LE.nombre.value);
document.LE.nombre.value = ""; }
</SCRIPT></BODY></HTML>
A. Goñi. Dpto. LSI, UPV/EHU
215

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
• 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()”

A. Goñi. Dpto. LSI, UPV/EHU


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
227
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
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 CLIENTE
llamadas son más simples… SERVIDOR

Lenguaje JAVA
Interfaces definidas en JAVA
Varias máquinas y S.O.
CORBA
RMI IIOP
JRMP / IIOP CLIENTE
TCP/IP SERVIDOR
CLIENTE
TCP/IP SERVIDOR Varios lenguajes: Java, C++…
Interfaces definidas en IDL
Varias máquinas y S.O.
Varios lenguajes .NET: C++, C#, . NET Remoting
VB.NET …
Interfaces definidas en .NET
(Sustituye a
Máquinas Windows (?) CLIENTE DCOM)
A. Goñi. Dpto. LSI, UPV/EHU SERVIDOR
233

HTTP en 5 minutos

• 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
CLIENTE HTTP SERVIDOR HTTP

Respuesta

Ejemplos de respuestas:
Ejemplos de comandos en peticiones:
Estados
GET Para leer una página Web
Datos
POST: Para enviar datos a una página Web
Códigos de error

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 Con telnet se puede abrir un socket
Trying 158.227.112.155... interactivo con un servidor HTTP
Connected to sipx55.si.ehu.es.
Escape character is '^]'.
Con GET se solicita una página web
GET /iso/jsp/public_html/pagina.jsp HTTP/1.0
(en este caso es un JSP)
// Añadir línea en blanco
HTTP/1.0 200 OK
Content-Type: text/html;charset=windows-1252
Set-Cookie2: JSESSIONID=pjqb72fy21;Version=1;Discard;Path="/iso"
Set-Cookie: JSESSIONID=pjqb72fy21;Path=/iso
Servlet-Engine: Tomcat Web Server/3.2.3 (JSP 1.1; Servlet 2.2; Java 1.3.1_02;
Windows 2000 5.0 x86; java.vendor=Sun Microsystems Inc.)

<html> El servidor HTTP envía datos (protocolo, código respuesta,


<head> información sobre el servidor,…)
<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
</h2> página HTML
</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...
HTTP en 5 minutosCon el comando POST, se pueden
Connected to sipx55.si.ehu.es.
Escape character is '^]'.
POST /iso/jsp/public_html/pagina.jsp HTTP/1.0
enviar datos al servidor HTTP.
Content-type: application/x-www-form-urlencoded
En este caso es el contenido de un
Content-length: 14
parámetro, pero en general, puede
Nombre=Alfredo ser cualquier fichero.
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
241
Documentos XML bien formados vs.
Documentos XML válidos
• Un documento XML está bien formado si cumple
las restricciones anteriores
– No hay nodo raíz, atributos no entre comillas,
mal anidamiento, etc…
• Pero es posible que no sea un documento XML
válido
– Nombres de etiquetas, atributos erróneos
– No aparición de alguna etiqueta obligatoria
–…
• Se puede definir la estructura de un documento
XML usando DTD o XML-Schema
• Qué etiquetas deben/pueden venir, qué
atributos, en qué orden, etc.
A. Goñi. Dpto. LSI, UPV/EHU
242
Llamadas a servicios remotos
usando XML y HTTP
Se puede definir una
estructura de documento
XML que describa una
llamada a un procedimiento
remoto

XML
HTTP
Se usa HTTP para la
transmisión de datos XML
CLIENTE entre las aplicaciones
CLIENTE y SERVIDOR
SERVIDOR

POST /gestorBilletes HTTP/1.0


Content-type: text/xml
Content-length: XX
Por ejemplo, para
<?xml version='1.0' encoding='windows-1252'?>
llamar al método <llamadaRemota>
getBillete(nombre), <getBillete>
<nombre>Pepe</nombre>
podríamos hacerlo así: </getBillete>
</llamadaRemota>
A. Goñi. Dpto. LSI, UPV/EHU
243
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
Se usa HTTP para la
CLIENTE transmisión de datos XML
entre las aplicaciones SERVIDOR
CLIENTE y 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


244
SOAP: Simple Object Access
Protocol

• 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
El mensaje se mete en un sobre (envelope)
SOAP header El mensaje se compone de una cabecera (header)
Bloque Header OPCIONAL y de un cuerpo (Body)
OBLIGATORIO
Bloque Header
La cabecera (header) se utiliza para enviar
SOAP Body información sobre identificadores de
Bloque Body transacciones, certificados de seguridad,
información sobre coordinación, etc.
Bloque Body

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
248
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
249
WSDL: Web Services Description
Language
• 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


250
WSDL: Web Services Description
Language
Documento WSDL TIPOS DE DATOS USADOS
Types (los de XML Schema)
DEL SERVICIO
DESCRIPCIÓN

Message MENSAJES DE
ABSTRACTA

Message Message Message


(REQUEST) (RESPONSE) (RESPONSE) PETICIÓN Y
(REQUEST)
RESPUESTA

PARA CADA
Operation 1 Operation 2
OPERACIÓN

SERVICIO ABSTRACTO
Interface (CONJUNTO DE
OPERACIONES)
DEL SERVICIO
DESCRIPCIÓN
CONCRETA

ENLACES A PROTOCOLOS
binding 1 binding 2 binding 3 DE TRANSPORTE

DIRECCIONES DE LOS
endpoint 1 endpoint 2 endpoint 3 ENLACES
TODAS LAS
IMPLEMENTACIONES DEL
Service
A. Goñi. Dpto. LSI, UPV/EHU SERVICIO
251
WSDL

Types

Message Message Message Message


(REQUEST) (RESPONSE) (REQUEST) (RESPONSE)

Operation 1 Operation 2

Interface

binding 1 binding 2 binding 3

endpoint 1 endpoint 2 endpoint 3

A. Goñi. Dpto. LSI, UPV/EHU Service


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) types
• 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


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 message


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


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 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


255
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 binding
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


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) port
• Descripción de un servicio como una colección de todos los
enlaces (bindings) de la misma interfaz
service

A. Goñi. Dpto. LSI, UPV/EHU


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


262
Se selecciona la clase Java para la
que se quiere crear el SW

A. Goñi. Dpto. LSI, UPV/EHU


263
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
264
Se indica la dirección del punto de
acceso

A. Goñi. Dpto. LSI, UPV/EHU


265
El WSDL se genera automáticamente

A. Goñi. Dpto. LSI, UPV/EHU


266

Punto
acceso

A. Goñi. Dpto. LSI, UPV/EHU


Creamos una clase Java cliente del SW 267

A. Goñi. Dpto. LSI, UPV/EHU


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 Mensaje SOAP con la


petición respuesta

A. Goñi. Dpto. LSI, UPV/EHU


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, WS-
Transaction, 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
import java.awt.*;
import java.awt.event.*;
public class ConsPrecioIU extends Frame {
Label label1 = new Label();
Panel panel1 = new Panel();
La interfaz de usuario Button button1 = new Button();
asociada a un caso de Button button2 = new Button();
uso llamado Panel panel2 = new Panel();
CONSULTAR PRECIO GridLayout gridLayout1 = new GridLayout(3,2);
Label label2 = new Label();
aparece a continuación,
TextField textField1 = new TextField();
junto con la clase Java Label label3 = new Label();
correspondiente: TextField textField2 = new TextField();
Label label4 = new Label();
TextField textField3 = new TextField();
public ConsPrecioIU() {
super();
try {
jbInit();
}
catch (Exception e) {
e.printStackTrace(); } }
// Continúa…
A. Goñi. Dpto. LSI, UPV/EHU
private void jbInit() throws Exception { 277
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) {...}
} LSI, UPV/EHU
A. Goñi. Dpto.
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 280

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
281

Solución

ConsPrecioIU “interface” PreciosLN


p: 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


282
EN LA PRESENTACIÓN AÑADIMOS UN ATRIBUTO
CON LA LÓGICA DEL NEGOCIO Y MÉTODO PARA
ASIGNARLA:
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


286
La siguiente solución no es
correcta…

ConsPrecioIU “interface” PreciosLN

usa getPrecioMan(): float


p: PreciosLN
getPrecioPer(): float,
getPrecioNar(): float

Precios
inicializarBD(): void
getPrecio(nombre:String): float
getPrecioMan(): float
getPrecioPer(): float,
getPrecioNar(): float
A. Goñi. Dpto. LSI, UPV/EHU
287
LA LÓGICA DEL NEGOCIO SE USA DESDE EL
MÉTODO DE ATENCIÓN AL EVENTO

void button1_actionPerformed(ActionEvent e) {
// En pr tenemos el objeto con la lógica del negocio
String kgManz = textField1.getText(); // idem. kgPer y KgNar
try{m=Float.parseFloat(kgManz);} catch (Exception ex) {m=0;}
try{p=Float.parseFloat(kgPer);} catch (Exception ex) {p=0;}
try{n=Float.parseFloat(kgNar);} catch (Exception ex) {n=0;}
float precio = m*pr.getPrecioMan()+ p*pr.getPrecioPer() +
n*pr.getPrecioNar();
Aviso a = new Aviso(this,"Precio es: "+precio);}
NO ES EXTENSIBLE. EL PRECIO DE LOS
PRODUCTOS NO DEPENDE DE LA CANTIDAD.
HABRÍA QUE CAMBIAR LA PRESENTACIÓN:
if (m>10) precioMan = pr.getPrecioMan()*0.9;
// idem. con resto de productos y descuentos
A. Goñi. Dpto. LSI, UPV/EHU
288

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
290
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);
}
ConsPrecioIU “interface” PreciosLN

usa calcularPrecio(datos: Enumeration): float


p: PreciosLN
obtenerProductos(): Enumeration

Precios

inicializarBD(): void
getPrecio(nombre:String): float
calcularPrecio(PrecCant:Enumeration ) : float
obtenerProductos(): Enumeration
A. Goñi. Dpto. LSI, UPV/EHU

También podría gustarte